UNPKG

@zerobytes/react-web-dynamic-tools

Version:

Package-module for fast-tracking common features to CRUD operations at ReactJS (web)

1,701 lines (1,515 loc) 92.4 kB
import React, { useCallback, useState, useEffect, useMemo } from 'react'; import PropTypes from 'prop-types'; import { useHistory } from 'react-router-dom'; import { makeStyles, Tooltip, IconButton, Typography, TextField, ListItem, ListItemSecondaryAction, FormLabel, InputAdornment, Paper, List, FormControlLabel, Checkbox, useTheme, useMediaQuery, Button, Card, CardContent, ExpansionPanel, ExpansionPanelSummary, ExpansionPanelActions, ExpansionPanelDetails, Dialog as Dialog$1, DialogTitle as DialogTitle$1, DialogContent as DialogContent$1, DialogActions as DialogActions$1, Chip } from '@material-ui/core'; import AddRounded from '@material-ui/icons/AddRounded'; import 'date-fns'; import { FieldTypes, FieldType, ComplexTypes, ModelBase } from '@zerobytes/object-model-js'; import DeleteIcon from '@material-ui/icons/DeleteRounded'; import SearchIcon from '@material-ui/icons/SearchRounded'; import VisibilityIcon from '@material-ui/icons/VisibilityRounded'; import VisibilityOffIcon from '@material-ui/icons/VisibilityOffRounded'; import IconButton$1 from '@material-ui/core/IconButton'; import EmailRounded from '@material-ui/icons/EmailRounded'; import LaunchRounded from '@material-ui/icons/LaunchRounded'; import { makeStyles as makeStyles$1 } from '@material-ui/styles'; import classNames from 'classnames'; import DateFnsUtils from '@date-io/date-fns'; import { MuiPickersUtilsProvider, KeyboardDateTimePicker } from '@material-ui/pickers'; import CancelRounded from '@material-ui/icons/CancelRounded'; import KeyboardReturnRounded from '@material-ui/icons/KeyboardReturnRounded'; import EditRounded from '@material-ui/icons/EditRounded'; import SaveRounded from '@material-ui/icons/SaveRounded'; import Dialog from '@material-ui/core/Dialog'; import DialogActions from '@material-ui/core/DialogActions'; import DialogContent from '@material-ui/core/DialogContent'; import DialogContentText from '@material-ui/core/DialogContentText'; import DialogTitle from '@material-ui/core/DialogTitle'; import Button$1 from '@material-ui/core/Button'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import _regeneratorRuntime from '@babel/runtime/regenerator'; import InfoIcon from '@material-ui/icons/InfoRounded'; var validateName = function validateName(name) { var nameRegex = /^[a-zA-Z]+$/; return nameRegex.test(name); }; var validateWebsite = function validateWebsite(webSite) { var webSiteRegex = /^((https?:\/\/)|(https?:\/\/)(www\.)|(www\.))?[a-zA-Z]{1,}[\.\-_]{0,}[a-zA-Z0-9%_\-.\+~#=]{1,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; return webSiteRegex.test(webSite); }; var validateEmail = function validateEmail(email) { var regEmail = /^(([^<>()[\]\\.,;:\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,}))$/; return regEmail.test(email); }; var validatePassword = function validatePassword(password) { var minLength = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 6; var pwdRegex = new RegExp("^.{".concat(minLength, ",}$")); return !pwdRegex.test(password); }; /** * Based on: https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript * * Will apply **three** rules: * * * normalize()ing to NFD Unicode normal form decomposes combined * graphemes into the combination of simple ones. The è of Crème ends up expressed as e + ̀. * * Using a regex character class to match the U+0300 → U+036F range, * it is now trivial to globally get rid of the diacritics, * which the Unicode standard conveniently groups as the Combining Diacritical Marks Unicode block. * * Removes any non-text/non-number char; * * @param {string} text The text to be cleansed * @param {Boolean} removeSpaces [optional] If spaces shold be removed * * @returns {string} */ var removeSpecialChars = function removeSpecialChars(text) { var removeSpaces = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var alphaNumericRegex = !removeSpaces ? /[^a-zA-Z0-9\s@]/g : /[^a-zA-Z0-9@]/g; return typeof text === 'string' ? text.normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(alphaNumericRegex, '') : text; }; /** * Tests whether the text itself is a valid e-mail or website; Known-types then * * @param {string} text The text to be tested * * @return {Boolean} */ var textIsKnownType = function textIsKnownType(text) { return typeof text === 'string' && (validateEmail(text) || validateWebsite(text)); }; var validations = /*#__PURE__*/Object.freeze({ __proto__: null, validateName: validateName, validateWebsite: validateWebsite, validateEmail: validateEmail, validatePassword: validatePassword, removeSpecialChars: removeSpecialChars, textIsKnownType: textIsKnownType }); function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function (obj) { return typeof obj; }; } else { _typeof = function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { return; } var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } /** * Hook for triggering a common enter-key-press action * * @param {Function} callback the function which will be triggered * * @returns {Function} the function to be used with an "onKeyPress" or any trigger */ var useEnterPress = function useEnterPress(callback) { var onEnterPress = useCallback(function (e) { if (e.key === 'Enter' && !!callback && typeof callback === 'function') callback(e); e.stopPropagation(); }, [callback]); return onEnterPress; }; /** * Firebase in-array slice limit */ var arraySliceLength = 10; /** * Utility for array slicing up to 10 itens * When building in-array for firebase-basic-service queries * * @param {string} property The property to be compared * @param {array} items List items of string */ var inArray = function inArray(property, items) { var filters = []; for (var i = 0; i < items.length / arraySliceLength; i += arraySliceLength) { filters.push(["".concat(property), 'in', items.slice(i, i + arraySliceLength)]); } return filters; }; var errorStyles = makeStyles({ root: { color: '#f44336', alignSelf: 'center', marginLeft: '10px', marginRight: '10px' } }); var textFieldStyles = makeStyles({ spacer: { marginBottom: '10px' } }); var filterTextField = makeStyles(function (theme) { return { root: {}, textField: { flex: 1, marginTop: theme.spacing(1), marginBottom: theme.spacing(1) } }; }); var viewInfoStyles = makeStyles(function (theme) { return { root: { marginBottom: theme.spacing(2) }, title: { marginBottom: '5px' }, detail: { marginTop: 5, marginBottom: 5, fontSize: 18, fontWeight: '100' } }; }); var viewInfoLink = makeStyles(function (theme) { return { root: {}, icon: { marginLeft: theme.spacing(1) } }; }); var listResultText = makeStyles({ root: { marginTop: 0, marginBottom: 10 } }); var listEmptyStyles = makeStyles(function (theme) { return { root: { marginTop: theme.spacing(1), marginBottom: theme.spacing(1), display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', '& > *': { flex: '0 0 auto', marginBottom: theme.spacing(2) } } }; }); /** * Renders a website link (anchor) for display * * @param {object} param0 props * @param {string} param0.text the text to be rendered * @param {Element} param0.icon the icon to be used * @param {Function} param0.i18n the translation source * @param {string} param0.type the type of the info * @param {Boolean} param0.external If it opens an external link */ var InfoWithIcon = function InfoWithIcon(_ref) { var text = _ref.text, icon = _ref.icon, i18n = _ref.i18n, _ref$iconProps = _ref.iconProps, iconProps = _ref$iconProps === void 0 ? null : _ref$iconProps, _ref$type = _ref.type, type = _ref$type === void 0 ? 'link' : _ref$type, _ref$external = _ref.external, external = _ref$external === void 0 ? true : _ref$external; var classes = viewInfoLink(); return React.createElement("div", { className: classes.root }, text, React.createElement(Tooltip, { title: i18n("view.text.info.".concat(type)), arrow: true }, React.createElement(IconButton, _extends({ variant: "text", className: classes.icon, "aria-label": text, size: "small", target: external ? '_blank' : '_self' }, iconProps), React.cloneElement(icon)))); }; InfoWithIcon.propTypes = { text: PropTypes.string, external: PropTypes.bool, i18n: PropTypes.func, type: PropTypes.oneOf(['link', 'website', 'email', 'phone']), icon: PropTypes.element }; /** * Renders an email "mailto:" (anchor) for display * * @param {object} param0 props * @param {string} param0.text the text to be rendered * @param {string} param0.i18n the translation source for tooltip/text * @param {string} param0.external [optional] if it opens an external link */ var EmailInfo = function EmailInfo(_ref) { var text = _ref.text, i18n = _ref.i18n, _ref$external = _ref.external, external = _ref$external === void 0 ? true : _ref$external; return React.createElement(InfoWithIcon, { text: text, icon: React.createElement(EmailRounded, null), i18n: i18n, external: external, type: "email", iconProps: { component: 'a', href: "mailto:".concat(text) } }); }; EmailInfo.propTypes = { text: PropTypes.string, external: PropTypes.bool }; /** * Renders a website link (anchor) for display * * @param {object} param0 props * @param {string} param0.text the text to be rendered * @param {string} param0.i18n the translation source for tooltip/text * @param {string} param0.external [optional] if it opens an external link */ var WebSiteInfo = function WebSiteInfo(_ref) { var text = _ref.text, i18n = _ref.i18n, _ref$external = _ref.external, external = _ref$external === void 0 ? true : _ref$external; return React.createElement(InfoWithIcon, { text: text, icon: React.createElement(LaunchRounded, null), i18n: i18n, external: external, type: "website", iconProps: { component: 'a', href: "".concat(text) } }); }; WebSiteInfo.propTypes = { text: PropTypes.string, external: PropTypes.bool }; var useStyles = makeStyles$1(function (theme) { return { root: { marginTop: theme.spacing(1), marginBottom: theme.spacing(1), display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-end', '& > *': { flex: '0 0 auto', marginLeft: theme.spacing(1) } } }; }); /** * * @param {React.ReactNodeArray} buttons */ var BottomButtons = function BottomButtons(_ref) { var buttons = _ref.buttons; var classes = useStyles(); return React.createElement("div", { className: classes.root }, buttons.map(function (button, key) { return React.cloneElement(button, { key: key }); })); }; BottomButtons.propTypes = { buttons: PropTypes.arrayOf(PropTypes.node) }; var EmptyRelation = function EmptyRelation(_ref) { var i18n = _ref.i18n; var classes = viewInfoStyles(); return React.createElement(Typography, { variant: "body2", className: classes.detail }, i18n('form.idof.not.informed')); }; EmptyRelation.propTypes = { i18n: PropTypes.func.isRequired }; var ErrorLabel = function ErrorLabel(_ref) { var children = _ref.children; var classes = errorStyles(); return children && React.createElement(Typography, { variant: "body2", className: classes.root }, children); }; var useStyles$1 = makeStyles(function (theme) { return { root: { display: 'flex', alignItems: 'flex-start', alignContent: 'flex-start', flexDirection: 'row', flexWrap: 'wrap', '& > .sibling-field': { flex: 1, flexGrow: 1, marginRight: '10px', minWidth: '100px', flexBasis: '120px', overflowWrap: 'break-word', '& .MuiFormControl-root': { width: '100%' } }, '& > .break-field': { flexBasis: '100%' } }, rootWithMarginTop: { marginTop: 15 } }; }); /** * Renders a default group-wrapper div, with possibility of margin-top-15 * * @param {*} param0 */ var FieldGroup = function FieldGroup(_ref) { var children = _ref.children, _ref$marginTop = _ref.marginTop, marginTop = _ref$marginTop === void 0 ? false : _ref$marginTop; var classes = useStyles$1(); return React.createElement("div", { className: classNames('field-group', classes.root, _defineProperty({}, classes.rootWithMarginTop, marginTop)) }, children); }; FieldGroup.propTypes = { children: PropTypes.oneOfType([PropTypes.element, PropTypes.node, PropTypes.arrayOf(PropTypes.element), PropTypes.arrayOf(PropTypes.node)]), marginTop: PropTypes.bool }; /** * Renders an input with defined type * * @param {Object} param0 */ var FormInput = function FormInput(_ref) { var label = _ref.label, _ref$type = _ref.type, type = _ref$type === void 0 ? 'text' : _ref$type, _ref$onChange = _ref.onChange, _onChange = _ref$onChange === void 0 ? function (e) { return console.error('FormInput:value:onChangeNotImplemented', e.target.value); } : _ref$onChange, otherProps = _objectWithoutProperties(_ref, ["label", "type", "onChange"]); return React.createElement(TextField, _extends({ variant: "outlined", type: type, label: label, onChange: function onChange(e) { _onChange(e); } }, otherProps)); }; FormInput.propTypes = { label: PropTypes.string, type: PropTypes.string, onChange: PropTypes.func }; var protectedFieldValue = '******', blankFieldPlaceholder = '-'; /** * TODO: comment/describe */ var DateDetail = function DateDetail(_ref) { var item = _ref.item, _ref$locale = _ref.locale, locale = _ref$locale === void 0 ? 'pt-br' : _ref$locale; var dateString = item.toLocaleDateString(locale), timeString = item.toLocaleTimeString(locale); return React.createElement("div", { key: 0, style: { flexBasis: '100%' } }, React.createElement(Typography, { style: { color: '#111', fontWeight: '700' } }, dateString + (!!timeString ? " ".concat(timeString) : ''))); }; var mergeSets = function mergeSets(set0, setOrObject1) { var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; var merged = null; if (defaultValue instanceof Array && setOrObject1 instanceof Array) { merged = [].concat(_toConsumableArray(set0), _toConsumableArray(setOrObject1)); } else if (_typeof(defaultValue) === 'object') { merged = [].concat(_toConsumableArray(set0), [Object.assign({}, setOrObject1)]); } else { merged = [].concat(_toConsumableArray(set0), [setOrObject1]); } return merged; }; var removeFromSet = function removeFromSet(set0, itemRemoving, indexRemoving) { var itemIsObject = itemRemoving instanceof Object && !!itemRemoving.uid, newList = _toConsumableArray(set0.filter(function (item, index) { return itemIsObject ? itemRemoving.uid !== item : index !== indexRemoving; })); return newList; }; /** * Checks whether a type should use a service * * @param {FieldType} Type The type being checked */ var typeShouldUseService = function typeShouldUseService(Type) { var should = false; //Type is a FieldType //And is specific shape //No service will exist behind if (!!Type && !!Type.complexType && Type instanceof FieldType && Type.complexType !== ComplexTypes.ShapedAs) { should = true; } return should; }; var typeInstance, typeService; /** * Creates a type service based on a Type instance * * @param {FieldType} Type The type being used for instance & service * @param {object} firebase The base object for connections */ var getTypeService = function getTypeService(Type, firebase) { typeInstance = !!Type && !!Type.Type && typeof Type.Type === 'function' && new Type.Type(); return !!typeInstance && typeInstance instanceof ModelBase && typeInstance.getService(firebase); }; /** * Will create an instance of Type=>Service, then request a list of objects, * based on a set/array of **uid-strings** specified at **objectWithProps** * * @param {string} property The prop name being used for reference * @param {FieldType} Type The type being used for instance & service * @param {ModelBase|object} objectWithProps The object which contains an array-prop with uid-strings * @param {object} firebase The base object for connections */ var getServiceList = function getServiceList(property, Type, objectWithProps, firebase) { typeService = getTypeService(Type, firebase); if (!typeService) throw Error('getServiceList-requires-valid-typeService-instance'); return typeService.filter(inArray('uid', objectWithProps[property])).list().then(function (result) { return Promise.resolve(result); }).catch(function (e) { throw e; }); }; /** * TODO: comment/describe * * @param {*} param0 */ var createConfiguredListItem = function createConfiguredListItem(_ref2) { var item = _ref2.item, listItemProperties = _ref2.listItemProperties, key = _ref2.key, onClick = _ref2.onClick, remove = _ref2.remove; var fields = []; if (listItemProperties) { listItemProperties.map(function (prop, i) { fields.push(React.createElement("div", { key: i, style: { flexBasis: '100%' } }, React.createElement(Typography, { style: { color: i > 0 ? '#666' : '#111', fontWeight: i > 0 ? '200' : '700' } }, typeof prop === 'function' ? prop(item) : item[prop]))); }); } else if (_typeof(item) !== 'object') { fields.push(React.createElement("div", { key: 0, style: { flexBasis: '100%' } }, React.createElement(Typography, { style: { color: '#111', fontWeight: '700' } }, item))); } else if (item instanceof Date) { fields.push(React.createElement(DateDetail, { item: item })); } return React.createElement(ListItem, { key: key, style: { flexWrap: 'wrap', borderBottom: '1px solid #ddd', cursor: onClick ? 'pointer' : 'normal' }, onClick: onClick }, fields, !!remove && React.createElement(ListItemSecondaryAction, null, React.createElement(IconButton$1, { edge: "end", onClick: function onClick() { remove(); } }, React.createElement(DeleteIcon, null)))); }; var searchIdOfTimeout; /** * TODO: comment/describe * * @param {ModelBase} model * @param {string} property * @param {object} values * @param {ModelBase} Type * @param {object} firebase * @param {function} i18n Translation base function. Has to receive an ID * @param {function} handleChange */ var createIdOfComponent = function createIdOfComponent(model, property, values, Type, firebase, i18n, handleChange) { var currentDialogValue = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null; var singleItem = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : true; var useOwnTitle = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : true; var config = model.$fieldConfig[property]; //Validating prior to using if (!config.searchField || !config.searchListItemProperties || !config.listItemProperties) return React.createElement("div", null, "NEED_TO_CONFIGURE_FIELD:", property, " | FieldType:IdOf", "<".concat(!!Type ? Type.name : 'undefined', ">"), "}", React.createElement("p", null, "MODEL: ", JSON.stringify(model))); var oService = new Type().getService(firebase), _useState = useState([]), _useState2 = _slicedToArray(_useState, 2), list = _useState2[0], setList = _useState2[1], _useState3 = useState(!!currentDialogValue ? currentDialogValue : !!singleItem ? null : []), _useState4 = _slicedToArray(_useState3, 2), selected = _useState4[0], setSelected = _useState4[1], _useState5 = useState(''), _useState6 = _slicedToArray(_useState5, 2), value = _useState6[0], setValue = _useState6[1]; if (!selected && values[property]) { if (!(values[property] instanceof Array && singleItem)) { clearTimeout(searchIdOfTimeout); searchIdOfTimeout = setTimeout(function () { oService.get(values[property]).then(function (r) { setSelected(r); }); }, 200); } else { clearTimeout(searchIdOfTimeout); searchIdOfTimeout = setTimeout(function () { oService.filter([['uid', 'in', values[property]]]).then(function (r) { setSelected(r); }); }, 200); } } else if (!!selected && selected instanceof Array && selected.length > 0 && (!currentDialogValue || currentDialogValue instanceof Array && currentDialogValue.length === 0)) { setSelected(currentDialogValue); } var select = function select(item) { return function () { setSelected(!!singleItem ? item : [].concat(_toConsumableArray(selected), [item])); setList([]); setValue(''); handleChange(property, item.uid, item); }; }; return React.createElement("div", { style: { position: 'relative' } }, useOwnTitle && React.createElement(Typography, { variant: "h5", className: "mb-10" }, i18n("".concat(model.getModelName(), ".form.").concat(property))), React.createElement("div", { style: { flex: 1 } }, React.createElement(FormInput, { variant: "outlined", value: value, style: { width: '100%' }, onChange: function onChange(e) { var text = e.target.value; setValue(text); clearTimeout(searchIdOfTimeout); if (!text) { setList([]); return; } var tend = text.substr(0, text.length - 1) + String.fromCharCode(text.substr(text.length - 1, 1).charCodeAt(0) + 1); searchIdOfTimeout = setTimeout(function () { oService.filter([[[config.searchField, '>=', text], [config.searchField, '<', tend], ['deleted', '==', false]]]).limit(5).list().then(function (r) { setList(r); }); }, 300); }, InputProps: { startAdornment: React.createElement(InputAdornment, { position: "start" }, React.createElement(SearchIcon, null)) } })), !!list.length && React.createElement(Paper, { elevation: 10, style: { position: 'absolute', zIndex: 10000, left: 0, right: 0 } }, React.createElement(List, { style: { minHeight: 65, maxHeight: 150, overflow: 'scroll' } }, list.map(function (item, i) { return createConfiguredListItem({ item: item, listItemProperties: config.searchListItemProperties, key: i, onClick: select(item) }); }))), !!selected && React.createElement("div", { className: "mt-10" }, !!singleItem && createConfiguredListItem({ item: selected, listItemProperties: config.listItemProperties, key: 0 }), !singleItem && selected.map(function (item, index) { return createConfiguredListItem({ item: item, listItemProperties: config.listItemProperties, key: index }); }))); }; var createFormComponent = function createFormComponent(_ref3) { var model = _ref3.model, property = _ref3.property, values = _ref3.values, field = _ref3.field, error = _ref3.error, label = _ref3.label, i18n = _ref3.i18n, handleChange = _ref3.handleChange; var component = null; component = createByType({ model: model, property: property, values: values, label: label, error: error, i18n: i18n, field: field, handleChange: handleChange, view: false }); return component; }; var createViewComponent = function createViewComponent(_ref4) { var model = _ref4.model, property = _ref4.property, field = _ref4.field, values = _ref4.values, label = _ref4.label, i18n = _ref4.i18n; var classes = viewInfoStyles(); return React.createElement("div", { className: classes.root }, React.createElement(FormLabel, { className: classes.title }, i18n(label)), React.createElement("div", { className: classes.detail, style: field.style.field }, createByType({ model: model, property: property, values: values, label: label, i18n: i18n, field: field, handleChange: null, view: true }))); }; var createByType = function createByType(_ref5) { var model = _ref5.model, property = _ref5.property, values = _ref5.values, label = _ref5.label, error = _ref5.error, i18n = _ref5.i18n, field = _ref5.field, handleChange = _ref5.handleChange, _ref5$view = _ref5.view, view = _ref5$view === void 0 ? false : _ref5$view; var component = null; switch (field.type) { case FieldTypes.Boolean: { component = createBooleanComponent({ property: property, values: values, label: label, i18n: i18n, field: field, handleChange: handleChange, view: view }); break; } case FieldTypes.Datetime: { component = createDatePickerComponent({ property: property, values: values, label: label, i18n: i18n, field: field, handleChange: handleChange, view: view }); break; } default: component = createTextComponent({ property: property, values: values, field: field, label: label, i18n: i18n, error: error, handleChange: handleChange, view: view }); break; } return component; }; var createDatePickerComponent = function createDatePickerComponent(_ref6) { var property = _ref6.property, values = _ref6.values, field = _ref6.field, label = _ref6.label, i18n = _ref6.i18n, error = _ref6.error, handleChange = _ref6.handleChange, _ref6$view = _ref6.view, view = _ref6$view === void 0 ? false : _ref6$view; var classes = textFieldStyles(), // [selectedDate, setSelectedDate] = useState(values[property] || ''), handleChg = function handleChg(date) { console.log('createDatePickerComponent:handleChg:date', date); // selectedDate handleChange(property, date); //Field has specific onChange function, runs after manipulation if (!!field.onChange && typeof field.onChange === 'function') field.onChange(null, values, property, date, handleChange); }; var value = ''; if (!!view) { if (values.hasOwnProperty(property)) { value = values[property]; } else { value = ''; } } else { if (values.hasOwnProperty(property) && values[property] !== '') { value = values[property]; } else { value = !!field.defaultValue ? field.defaultValue : ''; } } if (null !== value && '' !== value) { if (_typeof(value) === 'object' && !(value instanceof Date)) { if (typeof value.toDate === 'function') { value = value.toDate(); } else { value = new Date((!!value._seconds ? value._seconds : value.seconds) * 1000); } } else if (typeof value === 'string') { value = new Date(Date.parse(value)); } } return !!view ? null !== value && '' !== value ? typeof value.toDate === 'function' ? value.toDate().toLocaleString() : typeof value.toLocaleString === 'function' ? value.toLocaleString() : value : blankFieldPlaceholder : React.createElement(MuiPickersUtilsProvider, { utils: DateFnsUtils }, React.createElement(Tooltip, { arrow: true, title: i18n("form.datepicker.".concat(property)) }, React.createElement(React.Fragment, null, React.createElement(KeyboardDateTimePicker, _extends({ disabled: view, disableToolbar: true, inputVariant: "outlined", variant: "dialog", format: "dd/MM/yyyy HH:mm", margin: "normal", id: "date-picker-".concat(property), label: i18n(label) // value={selectedDate} , value: value, onChange: handleChg, KeyboardButtonProps: { 'aria-label': label }, error: !!error && !view, helperText: !view && !!error ? i18n("form.error.".concat(error)) : ' ', className: classes.spacer }, field.props))))); }; var createTextComponent = function createTextComponent(_ref7) { var property = _ref7.property, values = _ref7.values, field = _ref7.field, label = _ref7.label, i18n = _ref7.i18n, error = _ref7.error, handleChange = _ref7.handleChange, _ref7$view = _ref7.view, view = _ref7$view === void 0 ? false : _ref7$view; var classes = textFieldStyles(), _useState7 = useState(false), _useState8 = _slicedToArray(_useState7, 2), inputVisible = _useState8[0], setInputVisible = _useState8[1], handleVisibilityClick = function handleVisibilityClick(e) { //Toggling visibility return setInputVisible(!inputVisible); }; var component = null; component = !!view ? !!field.protected ? protectedFieldValue : !!values[property] && values[property] !== '' ? React.createElement(TextStyleByType, { text: values[property], i18n: i18n }) : blankFieldPlaceholder : React.createElement(FormInput //TODO: uncomment when usable // disabled={!!view} , _extends({ className: classes.spacer, InputProps: !!field.protected ? { endAdornment: React.createElement(InputAdornment, { position: "end" }, React.createElement(Tooltip, { title: i18n('button.password.showOrHide.tooltip'), arrow: true }, React.createElement(IconButton$1, { edge: "end", onClick: handleVisibilityClick }, inputVisible ? React.createElement(VisibilityOffIcon, null) : React.createElement(VisibilityIcon, null)))) } : {}, inputProps: { style: !!field.style.field ? field.style.field : {} }, label: i18n(label) //TODO: uncomment when usable // value={value} , value: values[property], type: fieldTypeByName(!!field.type ? field.type : FieldTypes.String, field.protected, inputVisible), onChange: function onChange(e) { //TODO: uncomment when usable // if (!!view) return false; handleChange(property, e.target.value); //Field has specific onChange function, runs after manipulation if (!!field.onChange && typeof field.onChange === 'function') field.onChange(e, values, property, e.target.value, handleChange); }, helperText: !view && !!error ? i18n("form.error.".concat(error)) : ' ', error: !!error && !view }, field.props)); return component; }; var createBooleanComponent = function createBooleanComponent(_ref8) { var property = _ref8.property, values = _ref8.values, label = _ref8.label, i18n = _ref8.i18n, field = _ref8.field, handleChange = _ref8.handleChange, _ref8$view = _ref8.view, view = _ref8$view === void 0 ? false : _ref8$view; var classes = textFieldStyles(), usableLabel = i18n(label), propValue = values[property], onChange = function onChange(e) { handleChange(property, e.target.checked); //Field has specific onChange function, runs after manipulation if (!!field.onChange && typeof field.onChange === 'function') field.onChange(e, values, property, e.target.checked, handleChange); }; return !!view ? i18n("boolean.view.".concat(undefined !== propValue && propValue !== null ? propValue.toString() : 'undefined')) : React.createElement(FormControlLabel, _extends({ className: classes.spacer, label: usableLabel, labelPlacement: "start", style: !!field.style.field ? field.style.field : {}, onChange: onChange, control: React.createElement(Checkbox, { value: property, color: "primary", checked: values[property], onChange: onChange, inputProps: { 'aria-label': usableLabel }, disabled: !!field.disabled || !!view }) }, field.props)); }; var fieldTypeByName = function fieldTypeByName(fieldType) { var fieldIsProtected = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var inputDataVisible = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; var fieldTypeName = ''; if (fieldIsProtected) { if (inputDataVisible) { return 'text'; } else { return 'password'; } } switch (fieldType) { case FieldTypes.Time: { fieldTypeName = 'time'; break; } case FieldTypes.Date: { fieldTypeName = 'date'; break; } case FieldTypes.Datetime: { fieldTypeName = 'datetime-local'; break; } case FieldTypes.Integer: case FieldTypes.Float: { fieldTypeName = 'number'; break; } case FieldTypes.String: default: { fieldTypeName = 'text'; break; } } return fieldTypeName; }; var TextStyleByType = function TextStyleByType(_ref9) { var text = _ref9.text, i18n = _ref9.i18n; if (validateEmail(text)) return React.createElement(EmailInfo, { text: text, i18n: i18n }); if (validateWebsite(text)) return React.createElement(WebSiteInfo, { text: text, i18n: i18n }); if (typeof text.toDate === 'function') return "".concat(text.toDate().toLocaleDateString()); return "".concat(text); }; /** * Custom hook for finding a list of data from an object array-prop * * @param {ModelBase} objectWithProps An object as source of data and string-uids * @param {string} property Property in question, the name * @param {FieldType} Type The type in question (complex should be) * @param {object} firebase With connection to a service * * @return {array} with a, array-list and a setList function */ var useListOfData = function useListOfData(objectWithProps, property, Type, firebase) { var _useState = useState([]), _useState2 = _slicedToArray(_useState, 2), list = _useState2[0], setList = _useState2[1], currentValues = objectWithProps[property], objectPropIsArray = currentValues instanceof Array; //TODO: URGENT review functionality useEffect(function () { if (!list || !list.length || objectPropIsArray && list.length !== currentValues.length) { //And is there a service behind? if (objectPropIsArray && objectWithProps[property].length > 0 && typeShouldUseService(Type)) { getServiceList(property, Type, objectWithProps, firebase).then(function (result) { setList(result); }); } else { //No service at all, sets raw data setList(objectWithProps[property]); } } }, [currentValues]); // }, [list, objectWithProps, property, Type]); return [list, setList]; }; /** * Provides a boolean whether to use mobile icon-buttons, given current window size * @returns {Boolean} true, icons might be rendered; false, may use texts */ function useMobileIconButtons() { var theme = useTheme(), matches = useMediaQuery(theme.breakpoints.down('md')); return matches; } /** * Provides access to the current window size object * @returns {{ width: number, height: number }} object with window size props */ function useWindowSize() { var isClient = (typeof window === "undefined" ? "undefined" : _typeof(window)) === 'object'; function getSize() { return { width: isClient ? window.innerWidth : undefined, height: isClient ? window.innerHeight : undefined }; } var _useState = useState(getSize), _useState2 = _slicedToArray(_useState, 2), windowSize = _useState2[0], setWindowSize = _useState2[1]; useEffect(function () { if (!isClient) { return false; } function handleResize() { setWindowSize(getSize()); } window.addEventListener('resize', handleResize); return function () { return window.removeEventListener('resize', handleResize); }; }, []); // Empty array ensures that effect is only run on mount and unmount return windowSize; } /** * A pattern-follower **add-button** * * @param {object} param0 * @param {string} param0.baseRoute * @param {function} param0.i18n * @param {function} param0.onClick */ var AddButton = function AddButton(_ref) { var i18n = _ref.i18n, _ref$baseRoute = _ref.baseRoute, baseRoute = _ref$baseRoute === void 0 ? null : _ref$baseRoute, _ref$onClick = _ref.onClick, _onClick = _ref$onClick === void 0 ? null : _ref$onClick, other = _objectWithoutProperties(_ref, ["i18n", "baseRoute", "onClick"]); var history = useHistory(), useIcon = useMobileIconButtons(), buttonText = useMemo(function () { return i18n('button.add'); }, [i18n]); return React.createElement(Tooltip, { title: i18n('button.add.tooltip'), arrow: true }, React.createElement(Button, _extends({ variant: "contained", color: "primary", onClick: function onClick(e) { !!_onClick && typeof _onClick === 'function' ? _onClick(e) : history.push("".concat(baseRoute, "/form/")); }, "aria-label": buttonText }, other), useIcon ? React.createElement(AddRounded, null) : buttonText)); }; AddButton.propTypes = { baseRoute: PropTypes.string, i18n: PropTypes.func.isRequired, onClick: PropTypes.func }; /** * A pattern-follower **cancel-button** * * @param {object} param0 * @param {function} param0.onClick * @param {string} param0.color * @param {function} param0.i18n */ var CancelButton = function CancelButton(_ref) { var onClick = _ref.onClick, i18n = _ref.i18n, _ref$color = _ref.color, color = _ref$color === void 0 ? 'secondary' : _ref$color, other = _objectWithoutProperties(_ref, ["onClick", "i18n", "color"]); var history = useHistory(), useIcons = useMobileIconButtons(), buttonText = useMemo(function () { return i18n('button.cancel'); }, [i18n]); return React.createElement(Tooltip, { title: i18n('button.cancel.tooltip'), arrow: true }, React.createElement(Button, _extends({ variant: "outlined", color: color, "aria-label": buttonText, children: useIcons ? React.createElement(CancelRounded, null) : buttonText, onClick: onClick || function () { return history.goBack(); } }, other))); }; CancelButton.propTypes = { onClick: PropTypes.func, i18n: PropTypes.func.isRequired, color: PropTypes.string }; /** * A pattern-follower **cancel-and-return-button** * * @param {object} param0 * @param {function} param0.onClick * @param {string} param0.color * @param {function} param0.i18n */ var CancelReturnButton = function CancelReturnButton(_ref) { var onClick = _ref.onClick, i18n = _ref.i18n, _ref$color = _ref.color, color = _ref$color === void 0 ? 'secondary' : _ref$color, other = _objectWithoutProperties(_ref, ["onClick", "i18n", "color"]); var history = useHistory(), useIcons = useMobileIconButtons(), buttonText = useMemo(function () { return i18n('button.cancel.return'); }, [i18n]), handleClick = function handleClick(e) { return !!onClick && typeof onClick === 'function' ? onClick(e) : history.goBack(); }; return React.createElement(Tooltip, { title: i18n('button.cancel.return.tooltip'), arrow: true }, React.createElement(Button, _extends({ variant: "outlined", color: color, "aria-label": buttonText, children: useIcons ? React.createElement(KeyboardReturnRounded, null) : buttonText, onClick: handleClick }, other))); }; CancelReturnButton.propTypes = { onClick: PropTypes.func, i18n: PropTypes.func.isRequired, color: PropTypes.string }; var useStyles$2 = makeStyles(function (theme) { return { root: { marginLeft: 5, color: 'rgba(255,255,255,1) !important', backgroundColor: 'rgba(216, 0, 0, 1) !important', '&:hover': { backgroundColor: 'rgba(195, 0, 0, 0.85) !important' } } }; }); /** * A pattern-follower **delete-button** * * @param {object} param0 * @param {function} param0.onClick * @param {function} param0.i18n */ var DeleteButton = function DeleteButton(_ref) { var onClick = _ref.onClick, i18n = _ref.i18n, other = _objectWithoutProperties(_ref, ["onClick", "i18n"]); var classes = useStyles$2(), useIcons = useMobileIconButtons(), buttonText = useMemo(function () { return i18n('button.delete'); }, [i18n]); return React.createElement(Tooltip, { title: i18n('button.delete.tooltip'), arrow: true }, React.createElement(Button, _extends({ variant: "contained", className: classes.root, onClick: onClick, "aria-label": buttonText }, other), useIcons ? React.createElement(DeleteIcon, null) : buttonText)); }; DeleteButton.propTypes = { onClick: PropTypes.func.isRequired, i18n: PropTypes.func.isRequired }; /** * A pattern-follower **edit-button** * * @param {object} param0 * @param {string} param0.baseRoute * @param {string} param0.id * @param {function} param0.i18n * @param {string} param0.color */ var EditButton = function EditButton(_ref) { var baseRoute = _ref.baseRoute, id = _ref.id, i18n = _ref.i18n, _ref$color = _ref.color, color = _ref$color === void 0 ? 'primary' : _ref$color, other = _objectWithoutProperties(_ref, ["baseRoute", "id", "i18n", "color"]); var history = useHistory(), useIcons = useMobileIconButtons(), buttonText = useMemo(function () { return i18n('button.edit'); }, [i18n]); return React.createElement(Tooltip, { title: i18n('button.edit.tooltip'), arrow: true }, React.createElement(Button, _extends({ variant: "contained", color: color, onClick: function onClick() { history.push("".concat(baseRoute, "/form/").concat(id)); }, "aria-label": buttonText }, other), useIcons ? React.createElement(EditRounded, null) : buttonText)); }; EditButton.propTypes = { baseRoute: PropTypes.string.isRequired, color: PropTypes.oneOf(['primary', 'secondary']), id: PropTypes.string, i18n: PropTypes.func.isRequired }; /** * A pattern-follower **save-button**. Required handler (onClick) * * @param {object} param0 * @param {function} param0.onClick * @param {function} param0.i18n * @param {string} param0.color */ var SaveButton = function SaveButton(_ref) { var onClick = _ref.onClick, i18n = _ref.i18n, _ref$color = _ref.color, color = _ref$color === void 0 ? 'primary' : _ref$color, other = _objectWithoutProperties(_ref, ["onClick",