@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
JavaScript
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",