Separated the model and the Container entity in order to remove any mutation operation
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing

This commit is contained in:
Siklos 2022-08-04 12:57:34 +02:00
parent 964d9a0e57
commit e2a099457c
7 changed files with 206 additions and 178 deletions

View file

@ -1,19 +1,20 @@
import React, { Children } from 'react';
import React from 'react';
import './App.scss';
import Sidebar from './Components/Sidebar/Sidebar';
import { ElementsSidebar } from './Components/ElementsSidebar/ElementsSidebar';
import { AvailableContainer } from './Interfaces/AvailableContainer';
import { Configuration } from './Interfaces/Configuration';
import { Container } from './Components/SVG/Elements/Container';
import { SVG } from './Components/SVG/SVG';
import { History } from './Components/History/History';
import { ContainerModel, IContainerModel, MakeIterator } from './Components/SVG/Elements/ContainerModel';
import Properties from './Interfaces/Properties';
interface IAppProps {
}
export interface IHistoryState {
MainContainer: Container | null,
SelectedContainer: Container | null,
MainContainer: IContainerModel | null,
SelectedContainer: IContainerModel | null,
TypeCounters: Record<string, number>
}
@ -56,19 +57,16 @@ class App extends React.Component<IAppProps> {
// Fetch the configuration from the API
fetchConfiguration().then((configuration: Configuration) => {
// Set the main container from the given properties of the API
const MainContainer = new Container(
const MainContainer = new ContainerModel(
null,
{
parent: null,
properties: {
id: 'main',
x: 0,
y: 0,
width: configuration.MainContainer.Width,
height: configuration.MainContainer.Height,
fillOpacity: 0,
stroke: 'black'
},
children: []
id: 'main',
x: 0,
y: 0,
width: configuration.MainContainer.Width,
height: configuration.MainContainer.Height,
fillOpacity: 0,
stroke: 'black'
}
);
@ -116,7 +114,7 @@ class App extends React.Component<IAppProps> {
* Select a container
* @param container Selected container
*/
public SelectContainer(container: Container) {
public SelectContainer(container: ContainerModel) {
const history = this.getCurrentHistory();
const current = history[history.length - 1];
this.setState({
@ -141,30 +139,21 @@ class App extends React.Component<IAppProps> {
if (current.SelectedContainer === null ||
current.SelectedContainer === undefined) {
throw new Error('Property was changed before selecting a Container');
throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
}
if (current.MainContainer === null ||
current.MainContainer === undefined) {
throw new Error('Property was changed before the main container was added');
throw new Error('[OnPropertyChange] Property was changed before the main container was added');
}
const pair = {} as Record<string, string | number>;
pair[key] = value;
const properties = Object.assign(current.SelectedContainer.props.properties, pair);
const props = {
...current.SelectedContainer.props,
properties
};
const newSelectedContainer = new Container(props);
const parent = current.SelectedContainer.props.parent;
if (parent === null) {
const clone: IContainerModel = structuredClone(current.SelectedContainer);
(clone.properties as any)[key] = value;
this.setState({
history: history.concat([{
SelectedContainer: newSelectedContainer,
MainContainer: newSelectedContainer,
SelectedContainer: clone,
MainContainer: clone,
TypeCounters: current.TypeCounters
}]),
historyCurrentStep: history.length
@ -172,15 +161,27 @@ class App extends React.Component<IAppProps> {
return;
}
const index = parent.props.children.indexOf(current.SelectedContainer);
parent.props.children[index] = newSelectedContainer;
const clone: IContainerModel = structuredClone(current.MainContainer);
const it = MakeIterator(clone);
let container: ContainerModel | null = null;
for (const child of it) {
if (child.properties.id === current.SelectedContainer.properties.id) {
container = child as ContainerModel;
break;
}
}
if (container === null) {
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
}
(container.properties as any)[key] = value;
const newMainContainer = new Container(Object.assign({}, current.MainContainer.props));
this.setState(
{
history: history.concat([{
SelectedContainer: newSelectedContainer,
MainContainer: newMainContainer,
SelectedContainer: container,
MainContainer: clone,
TypeCounters: current.TypeCounters
}]),
historyCurrentStep: history.length
@ -221,36 +222,52 @@ class App extends React.Component<IAppProps> {
} else {
newCounters[type]++;
}
const count = newCounters[type];
// Create maincontainer model
const structure: IContainerModel = structuredClone(current.MainContainer);
const clone = Object.assign(new ContainerModel(null, {} as Properties), structure);
// Find the parent
const it = MakeIterator(clone);
let parent: ContainerModel | null = null;
for (const child of it) {
if (child.properties.id === current.SelectedContainer.properties.id) {
parent = child as ContainerModel;
break;
}
}
if (parent === null) {
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
}
// Create the container
const parent = current.SelectedContainer;
const count = newCounters[type];
const container = new Container({
const newContainer = new ContainerModel(
parent,
properties: {
{
id: `${type}-${count}`,
x: 0,
y: 0,
width: properties?.Width,
height: parent.props.properties.height,
height: parent.properties.height,
...properties.Style
},
children: [],
userData: {
} as Properties,
[],
{
type
}
});
);
// And push it the the parent children
parent.props.children.push(container);
parent.children.push(newContainer);
// Update the state
const newMainContainer = new Container(Object.assign({}, current.MainContainer.props));
this.setState({
history: history.concat([{
MainContainer: newMainContainer,
MainContainer: clone,
TypeCounters: newCounters,
SelectedContainer: current.SelectedContainer
SelectedContainer: parent
}]),
historyCurrentStep: history.length
} as IAppState);
@ -283,7 +300,7 @@ class App extends React.Component<IAppProps> {
isOpen={this.state.isSVGSidebarOpen}
onClick={() => this.ToggleElementsSidebar()}
onPropertyChange={(key: string, value: string) => this.OnPropertyChange(key, value)}
selectContainer={(container: Container) => this.SelectContainer(container)}
selectContainer={(container: ContainerModel) => this.SelectContainer(container)}
/>
<button className='fixed z-10 top-4 right-12 text-lg bg-slate-200 hover:bg-slate-300 transition-all drop-shadow-md hover:drop-shadow-lg py-2 px-3 rounded-lg' onClick={() => this.ToggleElementsSidebar()}>&#9776; Elements</button>
<SVG selected={current.SelectedContainer}>