import * as React from 'react'; import './App.scss'; import { MainMenu } from './Components/MainMenu/MainMenu'; import { ContainerModel, findContainerById, IContainerModel, MakeIterator } from './Components/SVG/Elements/ContainerModel'; import Editor, { IEditorState } from './Editor'; import { AvailableContainer } from './Interfaces/AvailableContainer'; import { Configuration } from './Interfaces/Configuration'; export interface IHistoryState { MainContainer: IContainerModel | null, SelectedContainer: IContainerModel | null, SelectedContainerId: string, TypeCounters: Record } interface IAppProps { } interface IAppState { configuration: Configuration, history: IHistoryState[], historyCurrentStep: number, isLoaded: boolean } export class App extends React.Component { public state: IAppState; constructor(props: IAppProps) { super(props); this.state = { configuration: { AvailableContainers: [], AvailableSymbols: [], MainContainer: {} as AvailableContainer }, history: [], historyCurrentStep: 0, isLoaded: false }; } public NewEditor() { // 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 this.setState({ configuration, history: [ { MainContainer, SelectedContainer: MainContainer, TypeCounters: {} } ], historyCurrentStep: 0, isLoaded: true } as IAppState); }); } public LoadEditor(files: FileList | null) { 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); Revive(editorState); this.setState({ configuration: editorState.configuration, history: editorState.history, historyCurrentStep: editorState.historyCurrentStep, isLoaded: true } as IAppState); }); reader.readAsText(file); } public render() { if (this.state.isLoaded) { return (
); } else { return (
this.NewEditor()} loadEditor={(files: FileList | null) => this.LoadEditor(files)} />
); } } } /** * Fetch the configuration from the API * @returns {Configation} The model of the configuration for the application */ export async function fetchConfiguration(): Promise { const url = `${import.meta.env.VITE_API_URL}`; // The test library cannot use the Fetch API // @ts-ignore if (window.fetch) { return await fetch(url, { method: 'POST' }) .then((response) => response.json() ) as Configuration; } return new Promise((resolve) => { const xhr = new XMLHttpRequest(); xhr.open('POST', url, true); xhr.onreadystatechange = function() { // Call a function when the state changes. if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { resolve(JSON.parse(this.responseText)); } }; xhr.send(); }); } /** * Revive the Editor state * by setting the containers references to their parent * @param editorState Editor state */ function Revive(editorState: IEditorState): void { const history = editorState.history; for (const state of history) { if (state.MainContainer === null || state.MainContainer === undefined) { continue; } const it = MakeIterator(state.MainContainer); for (const container of it) { const parentId = container.properties.parentId; if (parentId === null) { container.parent = null; continue; } const parent = findContainerById(state.MainContainer, parentId); if (parent === undefined) { continue; } container.parent = parent; } const selected = findContainerById(state.MainContainer, state.SelectedContainerId); if (selected === undefined) { state.SelectedContainer = null; continue; } state.SelectedContainer = selected; } }