// import dependencies
import clone from 'clone-deep';
import { ReactSortable } from 'react-sortablejs';
import React, { useState, useEffect, createContext } from 'react';
import { Icon, Box, Fab, useTheme, Button, Tooltip, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions } from '../';
// import local modules
import Menu from './Menu';
import Field from './Field';
import onEnd from './drag';
import Config from './Config';
// create context
const DashupUIContext = createContext();
// global timer
let timer;
// global debounce
const debounce = (func, timeout = 1000) => {
// return debounced
return (...args) => {
// clear timeout previously
clearTimeout(timer);
// create new timeout
timer = setTimeout(() => func(...args), timeout);
};
};
// create menu component
const DashupUIForm = (props = {}) => {
// theme
const theme = useTheme();
// set saving
const [saving, setSaving] = useState(false);
const [config, setConfig] = useState(null);
// clean data
const cleanData = (obj = {}) => {
// cleaned
const cleanedObj = clone(obj);
// keys
Object.keys(cleanedObj).map((key) => {
// val
let val = cleanedObj[key];
// fix value
if (val && val.id) val = val.id;
if (val && typeof val.get === 'function') val = val.get('_id');
if (Array.isArray(val)) val = val.map((v) => typeof v?.get === 'function' ? v.get('_id') : (v?.id || v));
if (Array.isArray(val) && !val.length) return delete cleanedObj[key];
// set value
cleanedObj[key] = val;
// check obj
if (val && val instanceof Object && !(val instanceof Date)) {
cleanedObj[key] = cleanData(val);
}
});
// return obj
return cleanedObj;
};
// get ctx
const getCtx = () => {
// return
return {
onConfig : setConfig,
onSaving : setSaving,
// variables
id : props.id,
data : props.data,
page : props.page,
clean : props.clean || cleanData(props.data),
fields : props.fields,
dashup : props.dashup,
updating : props.updating,
available : props.available,
setFields : props.setFields,
setPrevent : props.setPrevent,
getFieldStruct : props.getFieldStruct,
};
};
// create context
const [ctx, setCtx] = useState(getCtx());
const [menu, setMenu] = useState(null);
const [remove, setRemove] = useState(null);
// use effect
useEffect(() => {
setCtx(getCtx());
}, [props.updating, props.fields, JSON.stringify(props.data), JSON.stringify(props.clean)]);
// set page
const setField = async (field, key, value, prevent) => {
// updates
let updates = {
[key] : value,
};
// find field
const actualField = (props.fields || []).find((f) => f.uuid === field.uuid);
// fix obj
if (typeof key === 'object') {
updates = key;
prevent = value;
}
// loading
setSaving(true);
// set to field
Object.keys(updates).forEach((k) => {
actualField[k] = updates[k];
});
// set page
await props.setFields(props.fields || [], prevent);
// loading
setSaving(false);
};
// on change
const onChange = (field, value) => {
// set value
props.data[field.name || field.uuid] = value;
// on data
debounce(props.setData, 200)(props.data);
};
// on remove
const onRemove = async (field) => {
// new columns
const newFields = (props.fields || []).filter((f) => f.uuid !== field.uuid);
// loading
setRemove(null);
setSaving(true);
// set page
await props.setFields(newFields);
// loading
setSaving(false);
};
// on hide config
const onHideConfig = async () => {
// set config
setConfig(null);
setSaving(true);
// set page
await props.setFields([...props.fields]);
// loading
setSaving(false);
};
// get fields
const getChildren = (parent = 'root') => {
// return filtered
return (props.fields || []).filter((f) => (f.parent || 'root') === parent).sort((a, b) => {
// return ordered
const oA = a.order || 0;
const bA = b.order || 0;
// return order
if (oA > bA) return 1;
if (bA > oA) return -1;
return 0;
});
};
// remove jsx
const removeJsx = (
);
// check wrapper
const fieldsJsx = getChildren(props.parent).map((field, i) => {
// return jsx
return (
{ field.break && }
);
});
// form wrapper
const formJsx = props.updating ? (
onEnd(e, props.fields, props.setFields, setSaving, setConfig, setMenu) }
handle=".moves"
style={ {
display : 'flex',
flexWrap : 'wrap',
minHeight : 30,
marginLeft : theme.spacing(-1),
} }
setList={ () => {} }
disabled={ !props.updating }
animation={ 0 }
swapThreshold={ 5 }
emptyInsertThreshold={ 1 }
>
{ fieldsJsx }
) : (
{ fieldsJsx }
);
// return jsx
return (
{ props.adds !== false && props.updating && (
setMenu(true) } color="primary" sx={ {
top : 0,
left : '50%',
zIndex : 10,
position : 'absolute',
transform : 'translateX(-50%) translateY(-50%)',
} }>
) }
{ !props.action ? formJsx : (
) }
{ menu && setMenu(null) } setField={ setField } /> }
{ config && onHideConfig() }
getForms={ props.getForms }
getField={ props.getField }
setField={ setField }
getFields={ props.getFields }
getChildren={ getChildren }
/>
}
{ removeJsx }
{ props.adds !== false && props.updating && (
setMenu(true) } color="primary" sx={ {
left : '50%',
bottom : 0,
zIndex : 10,
position : 'absolute',
transform : 'translateX(-50%) translateY(50%)',
} }>
) }
);
};
// create field
DashupUIForm.Menu = Menu(DashupUIContext);
DashupUIForm.Field = Field(DashupUIContext);
DashupUIForm.Config = Config(DashupUIContext);
// export default
export default DashupUIForm;