nope/resources/ui/layout/layout.tsx

280 lines
9.9 KiB
TypeScript
Raw Normal View History

2020-09-02 05:49:53 +00:00
/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @create date 2019-02-20 09:19:06
* @modify date 2020-07-22 22:06:39
* @desc [description]
*/
import React from 'react';
2020-10-26 07:39:34 +00:00
import { Col, Container, Modal, Nav, Row } from 'react-bootstrap';
2020-09-07 05:21:53 +00:00
import { FaTimesCircle } from 'react-icons/fa';
import DefaultNavbar from '../defaultNavbar';
2020-10-26 07:39:34 +00:00
import DynamicRenderer from '../dynamic/dynamicRenderer'
import { DynamicRendererProps } from '../dynamic/dynamicRenderer';
2020-09-02 15:00:03 +00:00
import Selection, { SelecitonProps } from './selection';
2020-09-02 05:49:53 +00:00
const mainStyle = {
minHeight: '90vh',
}
const sidebarStyle = {
padding: '10px',
background: "primary"
}
const contentStyle = {
2020-09-02 15:00:03 +00:00
padding: '10px',
}
2020-09-07 05:21:53 +00:00
export interface ITab {
label: string,
id: string,
delteable: boolean
}
2020-09-02 15:00:03 +00:00
export interface LayoutProps<T> extends SelecitonProps<T> {
onResize?: () => void;
2020-10-26 07:39:34 +00:00
onMount?: (ref: React.RefObject<any>, layout: Layout<T>) => void;
2020-09-02 15:00:03 +00:00
onUnmount?: () => void;
2020-09-07 11:05:40 +00:00
onNewTab?: () => Promise<ITab | false>;
2020-10-25 20:14:51 +00:00
onTabSelect?: (oldTabId: string, newTabId: string) => Promise<boolean>;
onTabDelete?: (tabId: string) => Promise<boolean>;
onNoTabSelected?: () => Promise<void>;
2020-09-07 05:21:53 +00:00
tabs?: {
2020-09-07 11:05:40 +00:00
allowNewTabs?: boolean;
2020-09-07 05:21:53 +00:00
active: string,
items: ITab[]
}
2020-09-02 15:00:03 +00:00
}
2020-10-26 07:39:34 +00:00
export interface ModalSettings {
content: DynamicRendererProps;
header: string;
size?: 'sm' | 'lg' | 'xl'
}
2020-09-02 15:00:03 +00:00
export interface LayoutState<T> {
2020-09-07 05:21:53 +00:00
update: null
2020-09-02 15:00:03 +00:00
}
class Layout<T> extends React.Component<LayoutProps<T>, LayoutState<T>> {
protected _ref: React.RefObject<any>;
protected _handleResize: () => void;
componentDidMount() {
const _this = this;
function handleResize() {
if (typeof _this.props.onResize === 'function') {
_this.props.onResize();
}
}
if (typeof this.props.onMount === 'function') {
2020-10-26 07:39:34 +00:00
this.props.onMount(this._ref, this);
2020-09-02 15:00:03 +00:00
}
this._handleResize = handleResize;
window.addEventListener('resize', this._handleResize);
}
componentWillUnmount() {
window.removeEventListener('resize', this._handleResize);
// Call the unmount
if (typeof this.props.onUnmount === 'function') {
this.props.onUnmount();
}
}
constructor(props) {
super(props);
this._ref = React.createRef();
}
2020-09-07 05:21:53 +00:00
public requestRerender() {
this.setState({
update: null
})
}
2020-10-26 07:39:34 +00:00
public openPopup(settings: ModalSettings){
this._modalSettings = settings;
this._modalVisible = true;
this.requestRerender();
const _this = this;
return () => {
_this._modalVisible = false;
_this.requestRerender();
}
}
protected _modalVisible = false;
protected _modalSettings: ModalSettings;
2020-09-02 15:00:03 +00:00
public render() {
2020-10-25 20:14:51 +00:00
const _this = this;
// Define a Select Tab Function.
const selectTab = async (id: string) => {
if (typeof this.props.onTabSelect === 'function') {
// Call the Async Function to select a Tab.
if (await this.props.onTabSelect(this.props.tabs.active, id)) {
this.props.tabs.active = id;
this.requestRerender();
return true;
}
return false;
} else {
// Assign the Tab ID
this.props.tabs.active = id;
this.requestRerender();
return true;
}
}
const delteTab = async (id: string, idx: number) => {
let removed = false;
if (typeof _this.props.onTabDelete === 'function') {
// Call the Async Function to select a Tab.
if (await _this.props.onTabDelete(id)) {
removed = true;
}
} else {
removed = true;
}
if (removed) {
// Remove the Items.
_this.props.tabs.items.splice(idx, 1);
// Check if the active element has been removed:
if (id == _this.props.tabs.active) {
// Assign the ID of the Element.
const _idx = _this.props.tabs.items.length > idx ? idx : _this.props.tabs.items.length - 1;
if (_idx !== -1){
// Assign the First ID.
const _newTabId = _this.props.tabs.items.length > _idx ? _this.props.tabs.items[_idx].id : null;
if (_newTabId !== null) {
if (!selectTab(_newTabId) && typeof _this.props.onNoTabSelected === 'function') {
// Send a Warning, that no Tabs has been selected
await _this.props.onNoTabSelected();
}
} else if (typeof _this.props.onNoTabSelected === 'function') {
// Send a Warning, that no Tabs has been selected
await _this.props.onNoTabSelected();
}
} else if (typeof _this.props.onNoTabSelected === 'function') {
// Send a Warning, that no Tabs has been selected
await _this.props.onNoTabSelected();
}
}
_this.requestRerender();
}
}
2020-09-02 15:00:03 +00:00
return (<>
2020-09-07 05:21:53 +00:00
<DefaultNavbar></DefaultNavbar>
2020-09-02 15:00:03 +00:00
<Container fluid style={mainStyle}>
<Row style={mainStyle}>
<Col className="col-md-2 d-none d-md-block bg-light sidebar-sticky" style={sidebarStyle}>
2020-09-07 11:05:40 +00:00
<Selection selection={this.props.selection} allowUserSelect={this.props.allowUserSelect} onItemSelected={this.props.onItemSelected}></Selection>
2020-09-02 15:00:03 +00:00
</Col>
<Col role="main" style={contentStyle}>
2020-09-07 05:21:53 +00:00
{this.props.tabs ?
2020-09-07 11:05:40 +00:00
<Nav variant="tabs" activeKey={this.props.tabs.active}>
2020-09-07 05:21:53 +00:00
{this.props.tabs.items.map((tab, idx) => {
2020-09-07 11:05:40 +00:00
if (tab.delteable && this.props.tabs.allowNewTabs) {
2020-09-07 05:21:53 +00:00
return (
<Nav.Item key={tab.id}>
<Nav.Link onSelect={_ => {
2020-10-25 20:14:51 +00:00
selectTab(tab.id);
2020-09-07 05:21:53 +00:00
}} eventKey={tab.id}>{tab.label}
<FaTimesCircle onClick={
2020-10-25 20:14:51 +00:00
(e) => {
2020-09-07 11:05:40 +00:00
e.preventDefault();
e.stopPropagation();
2020-10-25 20:14:51 +00:00
delteTab(tab.id, idx);
2020-09-07 05:21:53 +00:00
}
} ></FaTimesCircle>
</Nav.Link>
</Nav.Item>
);
} else {
return (
<Nav.Item key={tab.id}>
<Nav.Link onSelect={_ => {
2020-10-25 20:14:51 +00:00
selectTab(tab.id);
2020-09-07 05:21:53 +00:00
}} eventKey={tab.id}>{tab.label}</Nav.Link>
</Nav.Item>
);
}
})}
2020-09-07 11:05:40 +00:00
{this.props.tabs.allowNewTabs ?
<Nav.Item>
<Nav.Link eventKey='_NEW_ITEM' onSelect={async () => {
if (typeof this.props.onNewTab === 'function') {
const tab = await this.props.onNewTab();
2020-10-25 20:14:51 +00:00
2020-09-07 11:05:40 +00:00
if (tab && typeof tab === 'object') {
this.props.tabs.items.push(tab);
2020-10-25 20:14:51 +00:00
selectTab(tab.id);
2020-09-07 11:05:40 +00:00
}
}
}}>
+
</Nav.Link>
</Nav.Item> : ''
}
2020-09-07 05:21:53 +00:00
</Nav>
: ''
}
2020-09-02 15:00:03 +00:00
{/* style={{height: '100%'}} */}
<div ref={this._ref}></div>
</Col>
</Row>
</Container>
2020-10-26 07:39:34 +00:00
{/* Render a Modal dynamically. */}
{this._modalSettings != undefined?
<Modal
show={this._modalVisible}
backdrop="static"
keyboard={false}
size={this._modalSettings.size}
centered
>
<Modal.Header>
<Modal.Title>{this._modalSettings.header}</Modal.Title>
</Modal.Header>
<Modal.Body>
{/* Render the dynamic Component */}
<DynamicRenderer component={this._modalSettings.content.component} props={this._modalSettings.content.props}/>
</Modal.Body>
</Modal>
: ''}
2020-09-02 15:00:03 +00:00
</>);
}
2020-09-02 05:49:53 +00:00
}
2020-09-02 15:00:03 +00:00
export default Layout;