<repo_name>tomstejskal/AbraDAO<file_sep>/src/components/mainWindow.js
// @flow

import React from 'react';
import Model from '../core/model';
import Message from '../core/message';
import QueryEditor from './queryEditor';
import AppBar from 'material-ui/AppBar';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import type { MessageType, MapType } from '../core/types';

const menuClick = Message.new();

const queryMsg = Message.new();

type TModel = MapType;

const MainWindow = {
	init(): TModel {
		return Model.newMap({
			query: QueryEditor.init()
		});

	},

	update(model: TModel, msg: MessageType): TModel {
		switch (msg.type()) {
			case menuClick.type(): {
				alert('button clicked!');
				return model;
			}
			case queryMsg.type(): {
				return model.set('query',
					QueryEditor.update(model.get('query'), msg.data()));
			}
			default:
				return model;
		}
	},

	view(props: Object): Object {
		const { model, dispatch } = props;
		const QueryEditorView = QueryEditor.view;

		return (
			<MuiThemeProvider>
				<div>
					<AppBar title="Abra DAO" />
					<div style={{ padding: "0.5em 2em" }}>
						<div className="row">
							<div className="col-xs-12">
								<QueryEditorView
									model={model.get('query')}
									dispatch={msg => dispatch(queryMsg(msg))}
								/>
							</div>
						</div>
					</div>
				</div>
			</MuiThemeProvider>
		);
	}
};

export default MainWindow;
<file_sep>/src/index.js
// @flow

import App from './core/app';
import MainWindow from './components/mainWindow';
import './index.css';
import 'roboto-fontface/css/roboto/roboto-fontface.css';
import 'flexboxgrid/css/flexboxgrid.min.css';
import injectTapEventPlugin from 'react-tap-event-plugin';

// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
injectTapEventPlugin();

App.start(MainWindow);
<file_sep>/src/core/action.js
// @flow

import Message from './message';
import type { ComputationType, MessageConsType, ActionType, DispatchType } from './types';

const none_: ActionType = (dispatch: DispatchType) => dispatch(Message.none());

const Action = {
	none(): ActionType {
		return none_;
	},

	new(computation: ComputationType, successMsg: MessageConsType, failureMsg: MessageConsType): ActionType {
		return (dispatch: DispatchType) => {
			computation(
				successData => {
					dispatch(successMsg(successData))
				},
				failureData => {
					dispatch(failureMsg(failureData))
				}
			);
		}
	}
};

export default Action;
<file_sep>/src/core/app.js
// @flow

import React from 'react';
import ReactDOM from 'react-dom';
import Action from './action';
import type { AppType } from './types';

const App = {
	start(app: AppType): void {
		let model = app.init();
		const rootElem = document.getElementById('root');

		function render(dispatch) {
			const Main = app.view;
			ReactDOM.render(
				<Main model={model} dispatch={dispatch} />,
				rootElem
			);
		}

		function dispatch(msg) {
			const result = app.update(model, msg);

			let action = Action.none();

			if (Array.isArray(result)) {
				[model, action] = result;
			} else {
				model = result;
			}

			render(dispatch);

			if (action !== Action.none()) {
				action(dispatch);
			}
		}

		render(dispatch);
	}
};

export default App;
<file_sep>/src/core/types.js
// @flow

import type { Map, List } from 'immutable';

export type MapType = Map<any, any>;

export type ListType = List<any>;

export type ModelType = any;

export type MessageType = {
	type: () => Symbol,
	data: () => any
};

export type MessageConsType = (data: any) => MessageType;

export type DispatchType = (msg: MessageType) => void;

export type ActionType = (dispatch: DispatchType) => void;

export type ComputationType = (successData: any, failureData: any) => void;

export type AppType = {
	init: () => ModelType,
	update: (model: ModelType, msg: MessageType) => ModelType | [ModelType, ActionType],
	view: (props: Object) => Object
};
