Merged PR 16: Transform every single class components into functional component
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing

This improve greatly the performance and the code cleaning.
It allows us to separate the inseparable class methods into modules functions
This commit is contained in:
Eric Nguyen 2022-08-09 15:15:56 +00:00
parent 1fc11adbaa
commit d9e06537e8
33 changed files with 1298 additions and 1261 deletions

View file

@ -0,0 +1,6 @@
html,
body,
#root {
width: 100%;
height: 100%;
}

View file

@ -0,0 +1,79 @@
import React, { useEffect, useState } from 'react';
import './App.scss';
import { MainMenu } from '../MainMenu/MainMenu';
import { ContainerModel } from '../../Interfaces/ContainerModel';
import Editor, { IEditorState } from '../Editor/Editor';
import { LoadState } from './Load';
import { LoadEditor, NewEditor } from './MenuActions';
import { DEFAULT_CONFIG, DEFAULT_MAINCONTAINER_PROPS } from '../../utils/default';
// App will never have props
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface IAppProps {
}
export const App: React.FunctionComponent<IAppProps> = (props) => {
const [isLoaded, setLoaded] = useState<boolean>(false);
const defaultMainContainer = new ContainerModel(
null,
DEFAULT_MAINCONTAINER_PROPS
);
const [editorState, setEditorState] = useState<IEditorState>({
configuration: DEFAULT_CONFIG,
history: [{
MainContainer: defaultMainContainer,
SelectedContainer: defaultMainContainer,
SelectedContainerId: defaultMainContainer.properties.id,
TypeCounters: {}
}],
historyCurrentStep: 0
});
useEffect(() => {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const state = urlParams.get('state');
if (state === null) {
return;
}
fetch(state)
.then(
async(response) => await response.json(),
(error) => { throw new Error(error); }
)
.then((data: IEditorState) => {
LoadState(data, setEditorState, setLoaded);
}, (error) => { throw new Error(error); });
});
if (isLoaded) {
return (
<div>
<Editor
configuration={editorState.configuration}
history={editorState.history}
historyCurrentStep={editorState.historyCurrentStep}
/>
</div>
);
}
return (
<div className='bg-blue-100 h-full w-full'>
<MainMenu
newEditor={() => NewEditor(
setEditorState, setLoaded
)}
loadEditor={(files: FileList | null) => LoadEditor(
files,
setEditorState,
setLoaded
)}
/>
</div>
);
};

View file

@ -0,0 +1,13 @@
import { Dispatch, SetStateAction } from 'react';
import { Revive } from '../../utils/saveload';
import { IEditorState } from '../Editor/Editor';
export function LoadState(
editorState: IEditorState,
setEditorState: Dispatch<SetStateAction<IEditorState>>,
setLoaded: Dispatch<SetStateAction<boolean>>
): void {
Revive(editorState);
setEditorState(editorState);
setLoaded(true);
}

View file

@ -0,0 +1,71 @@
import { Dispatch, SetStateAction } from 'react';
import { Configuration } from '../../Interfaces/Configuration';
import { ContainerModel } from '../../Interfaces/ContainerModel';
import { fetchConfiguration } from '../API/api';
import { IEditorState } from '../Editor/Editor';
import { LoadState } from './Load';
export function NewEditor(
setEditorState: Dispatch<SetStateAction<IEditorState>>,
setLoaded: Dispatch<SetStateAction<boolean>>
): void {
// Fetch the configuration from the API
fetchConfiguration()
.then((configuration: Configuration) => {
// Set the main container from the given properties of the API
const MainContainer = new ContainerModel(
null,
{
id: 'main',
parentId: 'null',
x: 0,
y: 0,
width: configuration.MainContainer.Width,
height: configuration.MainContainer.Height,
fillOpacity: 0,
stroke: 'black'
}
);
// Save the configuration and the new MainContainer
// and default the selected container to it
const editorState: IEditorState = {
configuration,
history:
[
{
MainContainer,
SelectedContainer: MainContainer,
SelectedContainerId: MainContainer.properties.id,
TypeCounters: {}
}
],
historyCurrentStep: 0
};
setEditorState(editorState);
setLoaded(true);
}, (error) => {
// TODO: Implement an alert component
console.warn('[NewEditor] Could not fetch resource from API. Using default.', error);
setLoaded(true);
});
}
export function LoadEditor(
files: FileList | null,
setEditorState: Dispatch<SetStateAction<IEditorState>>,
setLoaded: Dispatch<SetStateAction<boolean>>
): void {
if (files === null) {
return;
}
const file = files[0];
const reader = new FileReader();
reader.addEventListener('load', () => {
const result = reader.result as string;
const editorState: IEditorState = JSON.parse(result);
LoadState(editorState, setEditorState, setLoaded);
});
reader.readAsText(file);
}