// import dependencies
import copy from 'copy-to-clipboard';
import { Tab } from '@mui/material';
import SimpleBar from 'simplebar-react';
import DashupUIPageAudit from './Audit';
import React, { useState, useEffect } from 'react';
import { TabContext, TabList, TabPanel } from '@mui/lab';
import { Icon, Form, View, Modal, Box, Avatar, Tooltip, Chip, Dialog, DialogTitle, DialogActions, DialogContentText, Stack, Button, DialogContent, IconButton, Menu, LoadingButton } from '../';
// let context
let DashupContext = null;
// create menu component
const DashupUIPageItem = (props = {}) => {
// copying
const [form, setForm] = useState(props.form);
const [audits, setAudits] = useState([]);
const [copying, setCopying] = useState(false);
const [tagOpen, setTagOpen] = useState(null);
const [updated, setUpdated] = useState(null);
const [prevent, setPrevent] = useState(false);
const [creating, setCreating] = useState(true);
const [removing, setRemoving] = useState(false);
const [userOpen, setUserOpen] = useState(null);
const [confirming, setConfirming] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [actualData, setActualData] = useState((props.item && props.item.get()) || {});
const [buttonLoading, setButtonLoading] = useState(null);
// destruct
const { page, dashup, getField, getModels, getFieldStruct, getForms, getFields } = props;
// use effect
useEffect(() => {
// set loading
if (props.item) {
// set data
setActualData((props.item && props.item.get()) || {});
} else if (!props.item) {
// set data
setActualData({});
}
}, [props.item && props.item.toJSON()]);
// on copy
const onCopy = (e, page, item) => {
// prevent
e.preventDefault();
e.stopPropagation();
// set loading
setCopying(true);
// timeout
setTimeout(() => setCopying(false), 2000);
// copy
copy(`https://${window.location.host}/app/${page.get('_id')}/${item.get('_id')}`);
};
// get tag types
const getTagFields = () => {
// check get field
if (!getField) return [];
// set types
let types = typeof props.tag !== 'undefined' ? props.tag : (props.page.get('data.tag') || []);
if (!Array.isArray(types)) types = [types];
// return fields
return types.map((f) => getField(f)).filter((f) => f);
};
// get user types
const getUserFields = () => {
// check get field
if (!getField) return [];
// set types
let types = typeof props.user !== 'undefined' ? props.user : (props.page.get('data.user') || []);
if (!Array.isArray(types)) types = [types];
// return fields
return types.map((f) => getField(f)).filter((f) => f);
}
// get form
const getForm = (forms) => {
// found
const found = forms.find((f) => f.get('_id') === form);
// check found
if (found) return found;
// current
const meta = forms.find((f) => f.get('_id') === (props.item && props.item.get('_meta.form')));
// check found
if (meta) return meta;
// return 0
return forms[0];
};
// get tags
const getTags = (tagField) => {
// tag field
if (!tagField) return [];
// get options
const options = tagField.options || [];
// check options
if (!options.length) return [];
// get value
let val = props.item.get(tagField.name || tagField.uuid) || [];
// set value
if (!Array.isArray(val)) val = [val].filter((v) => v);
// tags
return options.filter((t) => {
// return has tag
return val.includes(t.value);
});
};
// get users
const getUsers = (userField) => {
// check options
if (!userField) return [];
// get value
let val = props.item.get(userField.name || userField.uuid) || [];
// set value
if (!Array.isArray(val)) val = [val].filter((v) => v);
// tags
return val;
};
// get buttons
const getButtons = (placement = 'modal-footer') => {
// load buttons
return getModels().reduce((accum, model) => {
// check page
const connects = (model.get('connects') || []).filter((c) => c.type === 'button' && (c.placements || []).includes(placement));
// connects
accum.push(...connects);
// return accum
return accum;
}, []);
};
// has tags
const hasTags = () => {
// check page
if (!props.page) return;
// tag uuid
return !!(props.tag || props.page.get('data.tag') || []).length;
}
// has user
const hasUser = () => {
// check page
if (!props.page) return;
// tag uuid
return !!(props.user || props.page.get('data.user') || []).length;
};
// set data
const onData = (data) => {
// update data by keys
Object.keys(data).forEach((key) => {
// check key
if (key === '_id' || key === '_meta') return;
// set data
actualData[key] = data[key];
});
// set updated
setUpdated(new Date());
};
// on tag
const onUser = (field, value) => {
// get tag value
props.item.set(field.name || field.uuid, value);
// set updated
setUpdated(new Date());
// check id
if (props.item.get('_id')) {
props.item.save();
setUpdated(null);
}
};
// on tag
const onTag = (field, value) => {
// get tag value
let tagVal = (props.item.get(field.name || field.uuid) || []);
// check array
if (!Array.isArray(tagVal)) tagVal = [tagVal].filter((t) => t && typeof t === 'string');
// check includes
if (tagVal.includes(value)) {
tagVal = tagVal.filter((v) => v !== value);
} else {
tagVal.push(value);
}
// set and save
props.item.set(field.name || field.uuid, field.multiple ? tagVal : tagVal.pop());
// set updated
setUpdated(new Date());
// check id
if (props.item.get('_id')) {
props.item.save();
setUpdated(null);
}
};
// on hide
const onHide = () => {
// check updated
if (updated) {
// check confirm
if (confirming) {
setConfirming(false);
props.onHide();
} else {
setConfirming(true);
}
} else {
// hide immediately
props.onHide();
}
};
// on remove
const onRemove = async (e) => {
// prevent
e.preventDefault();
e.stopPropagation();
// loading remove
setSubmitting(true);
// submit form
await props.item.remove();
// loading remove
setRemoving(false);
setSubmitting(false);
onHide();
};
// on create
const onCreate = (dashup) => {
// unset for form remove
setCreating(false);
setActualData({});
props.setItem(new dashup.Model({}, dashup));
setTimeout(() => setCreating(true), 200);
};
// on button
const onButton = async (e, button) => {
// set loading
setButtonLoading(button?.uuid);
// load key
await dashup.action({
type : 'connect',
page : props.page.get('_id'),
struct : 'button',
}, 'trigger', {
button,
item : props.item && props.item.get('_id'),
model : getModels()[0].get('_id'),
});
// set loading
setButtonLoading(null);
};
// on submit
const onSubmit = async (e, form) => {
// prevent
e.preventDefault();
e.stopPropagation();
// check submitting
if (submitting) return;
// submitting
setSubmitting(true);
// creating
const creating = !props.item?.get('_id');
// submit form
const result = await props.dashup.action({
type : 'page',
page : props.page.get('_id'),
form : form.get('_id'),
model : (props.item && props.item.get('_meta.model')) || form.get('data.model'),
struct : 'form',
}, 'form.submit', {
_id : props.item ? props.item.get('_id') : null,
...actualData,
});
// set to item
props.item.set('_id', result._id);
props.item.set('_meta', result._meta);
// set item
if (creating && result._id && typeof eden !== 'undefined') {
// url
const url = `/app/${props.page.get('_id')}/${result._id}`;
// check state
const state = Object.assign({}, {
prevent : true,
}, eden.router.history.location.state);
// replace history
eden.router.history.replace({
pathname : url,
}, state);
}
// submitting
setUpdated(null);
setSubmitting(false);
};
// audits
useEffect(() => {
// check eden
if (typeof eden === 'undefined') return;
// audits
let localAudits = audits || [];
// check item
if (!props.item || !props.item.get('_id')) {
localAudits = [];
return setAudits([]);
}
// on audits
const onAudits = (changes = []) => {
// loop audits
changes.forEach((audit) => {
// new audits
localAudits = localAudits.filter((a) => a.id !== audit.id);
// push new audit
localAudits.push(audit);
});
// update audits
setAudits([...localAudits]);
};
// load audits
eden.dashup.socket.on(`audit.${props.item.get('_id')}`, onAudits);
eden.dashup.rpc({}, 'audit.subscribe', props.item.get('_id')).then(onAudits);
// return unlisten
return () => {
eden.dashup.rpc({}, 'audit.unsubscribe', props.item.get('_id'));
eden.dashup.socket.off(`audit.${props.item.get('_id')}`, onAudits);
};
}, [props.item && props.item.get('_id')]);
// get forms
const forms = props.page.get('data.sorted.0') ? props.page.get('data.sorted').map((form) => props.dashup.page(form)).filter((f) => f) : getForms();
const chosenForm = getForm(forms);
// return jsx
return (
<>
{ audits.map((audit, i) => {
// changes
if (!audit?.changes?.length) return null;
// return jsx
return (
);
}) }
) }
>
{ !!props.item.get('_id') && (
onCopy(e, page, props.item) }>
{ copying ? (
) : (
) }
) }
{ !!hasTags() && (
getTagFields().map((type, i) => {
// return jsx
return (
{ getTags(type).map((tag, a) => {
// get color
const color = tag.color?.hex;
// return jsx
return (
setTagOpen({ type : type.uuid, el : e.target }) }
onDelete={ () => {} }
/>
);
}) }
setTagOpen({ type : type.uuid, el : e.target }) }>
);
})
) }
{ !!hasUser() && (
getUserFields().map((type, i) => {
// return jsx
return (
{ getUsers(type).map((user, a) => {
// return jsx
return (
}
onClick={ (e) => setUserOpen({ type : type.uuid, el : e.target }) }
onDelete={ () => {} }
/>
);
}) }
setUserOpen({ type : type.uuid, el : e.target }) }>
);
})
) }
{ !!creating && (
setForm(v) }>
{ forms.map((t, i) => {
// return jsx
return ;
}) }
{ forms.map((t, i) => {
// return jsx
return (
);
}) }
) }
{ !!props.item.get('_id') && (
setRemoving(true) }>
) }
{ !!props.item.get('_id') && (
onCreate(dashup) }>
) }
{ getButtons().map((button) => {
// return buttons
return (
onButton(e, button) } loading={ buttonLoading === button.uuid }>
{ button.label || button.name || button.uuid }
);
}) }
onSubmit(e, chosenForm) } disabled={ (!props.saveEmpty && !updated) || prevent || submitting } loading={ submitting }>
{ submitting ? 'Submitting...' : 'Submit' }
>
);
}
// wrapper
const DashupUIPageItemWrapper = (props = {}) => {
// return jsx
return (
{ (data) => {
// return jsx
return (
);
} }
)
};
// export default page menu
export default (ctx) => {
// use context
DashupContext = ctx;
// return actual component
return DashupUIPageItemWrapper;
};