<commit_before>// maybe add a kind of stack trace next time
function ContextError(pos, endPos, node, msg){
    this.pos = pos;
    this.endPos = endPos;
    this.node = node;
    this.msg = msg;

    this.toString = function(){
        return this.msg+"; "+this.node;
    }
}

function InternalError(pos, endPos, node, msg, jspos, filename){
    this.pos = pos;
    this.endPos = endPos;
    this.node = node;
    this.msg = msg;
    this.jspos = jspos;
    this.filename = filename

    this.toString = function(){
        return this.msg+" at "+this.jspos+" while evaluating "+this.node;
    }
}

function MtyInterpreter(ast, printfn, readfn){
    this.ast = ast;

    var _printfn = printfn || function(msg){ console.log(msg); };
    var _readfn = readfn || function(){ return prompt(); };

    var _abortBlock = undefined;
    var _actions = {};
    var currentNode = undefined;

    var _eval = function(node, lvalue){
        lvalue = lvalue || false;
        currentNode = node;
        return _actions[node.name](node, lvalue);
    };
    var _blockStack = [];

    var _returnValue = undefined;
    var _getReturnValue = function(){
        var val = _returnValue;
        _returnValue = undefined;
        return val;
    };

    var _setReturnValue = function(val){
        _returnValue = val;
    };

    var _getTypeDist = function(lvalue, rvalue){
        // TODO: use inheritance
        if(lvalue.type == "Object"){
            return 1;
        }
        if(lvalue.type != rvalue.type){
            return -1;
        }
        return 0;
    };

    var _resolveSelf = function(){
        var blockIndex = _blockStack.length-1;
        var result = undefined;
        while((result == undefined)&&(blockIndex >= 0)){
            result = _blockStack[blockIndex].instance;
            blockIndex--;
        }
        if(result == undefined){
            throw new ContextError(currentNode.pos, currentNode.endPos,
                        currentNode, "The 'self' keyword may only be used "
                        + "inside methods of a class'");
        }
        return result;
    };

    var _resolveVariable = function(variableName, isMemberAccess){
        var blockIndex = _blockStack.length-1;
        var result = undefined;
        if(isMemberAccess){
            var classBlock = {blockType : undefined};
            while((classBlock.blockType != "class")&&(blockIndex >= 0)){
                classBlock = _blockStack[blockIndex];
                blockIndex--;
            }
            if(classBlock.blockType == "class"){
                result = classBlock.resolveVariable(variableName);
            }
        }
        else {
            while((result == undefined)&&(blockIndex >= 0)){
                if((_blockStack[blockIndex].blockType != "class")
                    ||(_blockStack[blockIndex] == _blockStack.peek()))
                {
                    result = _blockStack[blockIndex]
                                .resolveVariable(variableName);
                }
                blockIndex--;
            }
        }
        return result;
    };

    var _resolveFunction = function(functionName, isMemberAccess){
        var blockIndex = _blockStack.length-1;
        var result = undefined;
        // TODO: overload resolution
        if(isMemberAccess){
            var classBlock = {blockType : undefined};
            while((classBlock.blockType != "class")&&(blockIndex >= 0)){
                classBlock = _blockStack[blockIndex];
                blockIndex--;
            }
            if(classBlock.blockType == "class"){
                result = classBlock.resolveFunction(functionName);
            }
        }
        else {
            while((result == undefined)&&(blockIndex >= 0)){
                if((_blockStack[blockIndex].blockType != "class")
                    ||(_blockStack[blockIndex] == _blockStack.peek()))
                {
                    result = _blockStack[blockIndex]
                            .resolveFunction(functionName);
                }
                blockIndex--;
            }
        }
        return result;
    };

    var _resolveClass = function(className){
        var blockIndex = _blockStack.length-1;
        var result = undefined;

        while((result == undefined)&&(blockIndex >= 0)){
            result = _blockStack[blockIndex].resolveClass(className);
            blockIndex--;
        }
        return result;
    };

    // -------------------------------------------------------------------------
    // -- evaluation action functions ------------------------------------------
    // -------------------------------------------------------------------------

    _actions['WhileLoop'] = function(node) {
        while(_eval(node.condition).getValue()){
            _eval(node.body);
            if(_abortBlock != undefined){
                if(_abortBlock.command == "skip"){
                    _abortBlock = undefined;
                    continue;
                }
                else if(_abortBlock.command == "break"){
                    _abortBlock = undefined;
                    break;
                }
                else if(_abortBlock.command == "return"){
                    break;
                }
            }
        }
    }

    _actions['IfStatement'] = function(node) {
        if(_eval(node.condition).getValue()){
            _eval(node.trueBody);
        }
        else{
            _eval(node.falseBody);
        }
    }

    _actions['Literal'] = function(node) {
        return node;
    }

    _actions['SelfExpression'] = function(node) {
        return _resolveSelf();
    }

    _actions['MethodCall'] = function(node) {
        _eval(node.memberAccess);
    }

    var classInstantiation = function(node, clsDecl){
        var instance = clsDecl.createInstance(node);
        instance.block.instance = instance;

        // evaluate the initialization statements
        _eval(instance.block);

        // call the initializer (if there is one)
        _blockStack.push(clsDecl.block);
        _blockStack.push(instance.block);
        try{
            var initCall = mtyParser.createFunctionCall(node.pos, node.endPos,
                                    "initializer", node.parameters);
            initCall.isMemberAccess = true;
            _eval(initCall);
        } catch(err) {
            if(err.msg != "The method 'initializer' could not be resolved."){
                throw(err);
            }
        }
        _blockStack.pop();
        _blockStack.pop();

        return instance;
    }

    _actions['FunctionCall'] = function(node) {
        var clsDecl = _resolveClass(node.functionName);
        if(clsDecl != undefined){
            return classInstantiation(node, clsDecl);
        }else{
            var funDecl = _resolveFunction(node.functionName,
                                            node.isMemberAccess);
            if(funDecl == undefined){
                switch(node.functionName){
                    case "print":
                        var param = _eval(node.parameters[0]);
                        _printfn(""+param.getValue());
                        break;
                    case "println":
                        var param = _eval(node.parameters[0]);
                        _printfn(""+param.getValue() + "\n");
                        break;
                    default:
                        var funType = node.isMemberAccess ?
                                    "method" : "function";
                        throw new ContextError(node.pos, node.endPos, node,
                            "The "+funType+" '"+node.functionName
                            +"' could not be resolved.");
                }
            }
            else{
                var contents = [];
                var argc = node.parameters ? node.parameters.length : 0;
                var parc = funDecl.parameters ? funDecl.parameters.length : 0;

                for(var i=0; i < parc; i++){
                    if(i < argc){
                        var param = funDecl.parameters[i];
                        if(Array.isArray(param)){ param = param[0]; }
                        var arg = node.parameters[i];
                        var varaccess = mtyParser.createVariableAccess(arg.pos,
                                                            arg.endPos,
                                                            param.variableName);
                        contents.push(param);
                        contents.push(mtyParser.createAssignment(arg.pos,
                                                                arg.endPos,
                                                                varaccess, arg));
                    }
                    else{
                        var param = funDecl.parameters[i][0];
                        var assign = funDecl.parameters[i][1];
                        contents.push(param);
                        contents.push(assign);
                    }
                }
                var paramBlock = mtyParser.createBlock(funDecl.pos, funDecl.endPos,
                                                        contents, "parameters");

                _eval(paramBlock);
                // the param block is a parent block of the function body block
                // this way, the parameter declarations are visible within the
                // function body
                _blockStack.push(paramBlock);
                _eval(funDecl.body);
                _blockStack.pop();

                _abortBlock = undefined;
                return _getReturnValue();
        }
        }
    }

    /* declarations are not processed by the interpreter for now
       this may be used when a REPL is implemented
    _actions['VariableDeclaration'] = function(node) {}
    _actions['FunctionDeclaration'] = function(node) {}
    _actions['ClassDeclaration'] = function(node) {}
    */

    _actions['VariableAccess'] = function(node, lvalue) {
        var vardecl = _resolveVariable(node.variableName, node.isMemberAccess);
        if(vardecl == undefined){
            var varType = node.isMemberAccess ? "attribute" : "variable";
            throw new ContextError(node.pos, node.endPos,
                        node, "The "+varType+" '"+node.variableName
                        +"' could not be resolved.");
        }
        if(! lvalue){vardecl = vardecl.getValue(); }
        return vardecl;
    }

    _actions['Assignment'] = function(node) {
        var lvalue = _eval(node.left, true);
        var rvalue = _eval(node.right);
        if(_getTypeDist(lvalue, rvalue) < 0){
            throw new ContextError(node.pos, node.endPos,
                        node, "Type error: rhs expression type "+
                        rvalue.type + " does not match lhs type "+lvalue.type);
        }
        lvalue.value = rvalue;
    }

    _actions['CommandStatement'] = function(node) {
        switch(node.command){
            case 'return':
                if(node.argument){
                    _setReturnValue(_eval(node.argument));
                }
                _abortBlock = node;
                break;
            case 'yield': // TODO: implement
                break;
            case 'raise': // TODO: implement
                break;
            case 'skip': // node.argument always undefined
                _abortBlock = node;
                break;
            case 'break': // node.argument always undefined
                _abortBlock = node;
                break;
        }
    }

    var _checkAbortBlock = function(node){
        if((_abortBlock.command == "break")||(_abortBlock.command == "skip")){
            if((node.blockType == "function")||(node.blockType == "module")){
                throw new ContextError(node.pos, node.endPos, node,
                        "Invalid "+_abortBlock.command
                        +" statement outside loop.");
            }
        }
        else if(_abortBlock.command == "return"){
            if(node.blockType == "module"){
                throw new ContextError(node.pos, node.endPos, node,
                        "Invalid return statement outside function.");

            }
        }
    }

     _actions['Block'] = function(node) {
        _blockStack.push(node);
        var stmts = node.statements;
        for(var i = 0; i < stmts.length; i++){
            _eval(stmts[i]);
            if(_abortBlock != undefined){
                _checkAbortBlock(node);
                break;
            }
        }
        _blockStack.pop();
    }

    _actions['UnaryExpression'] = function(node) {
        switch(node.operator){
            case '-':
                break;
            case 'not':
                break;
        }
    }

    var _memberAccess = function(node, lvalue){
        var left = _eval(node.left).getValue()
        var right;
        _blockStack.push(left.block);
        node.right.isMemberAccess = true;
        right = _eval(node.right, lvalue);
        _blockStack.pop();

        return right;
    }

    _actions['BinaryExpression'] = function(node, lvalue) {
        if(node.op == "."){
            return _memberAccess(node, lvalue);
        }

        var left = _eval(node.left).getValue();
        var right = _eval(node.right).getValue();

        // result = new Expression();
        result = mtyParser.createExpression();
        switch(node.op){
            case '+':
                result.value = left + right;
                break;
            case '-':
                result.value = left - right;
                break;
            case '*':
                result.value = left * right;
                break;
            case '/':
                result.value = left / right;
                break;
            case '%':
                result.value = left % right;
                break;
            case '^':
                result.value = Math.pow(left, right);
                break;
            case '=':
                result.value = left === right;
                break;
            case '!=':
                result.value = left !== right;
                break;
            case '<':
                result.value = left < right;
                break;
            case '>':
                result.value = left > right;
                break;
            case '<=':
                result.value = left <= right;
                break;
            case '>=':
                result.value = left >= right;
                break;
        }
        return result;
    }

    // -------------------------------------------------------------------------
    // -------------------------------------------------------------------------

    this.run = function(){
        try{
            _eval(ast);
        }
        catch(err){
            if(err.constructor.name == "ContextError"){
                err.type = "ContextError";
                throw err;
            }
            else{
                err.type = "__internal__";
                if(currentNode == undefined){
                    currentNode = {
                        name : "",
                        pos : mtyParser.createPos(-1,-1),
                        endPos : mtyParser.createPos(-1,-1)
                    }
                }
                var err = new InternalError(currentNode.pos, currentNode.endPos,
                                        currentNode, err.message,
                                        mtyParser.createPos(err.lineNumber,
                                                            err.columnNumber),
                                        err.fileName);
                err.type = "InternalError";
                throw err;
            }
        }
    }
}<commit_msg>checking argument count of function calls<commit_after>// maybe add a kind of stack trace next time
function ContextError(pos, endPos, node, msg){
    this.pos = pos;
    this.endPos = endPos;
    this.node = node;
    this.msg = msg;

    this.toString = function(){
        return this.msg+"; "+this.node;
    }
}

function InternalError(pos, endPos, node, msg, jspos, filename){
    this.pos = pos;
    this.endPos = endPos;
    this.node = node;
    this.msg = msg;
    this.jspos = jspos;
    this.filename = filename

    this.toString = function(){
        return this.msg+" at "+this.jspos+" while evaluating "+this.node;
    }
}

function MtyInterpreter(ast, printfn, readfn){
    this.ast = ast;

    var _printfn = printfn || function(msg){ console.log(msg); };
    var _readfn = readfn || function(){ return prompt(); };

    var _abortBlock = undefined;
    var _actions = {};
    var currentNode = undefined;

    var _eval = function(node, lvalue){
        lvalue = lvalue || false;
        currentNode = node;
        return _actions[node.name](node, lvalue);
    };
    var _blockStack = [];

    var _returnValue = undefined;
    var _getReturnValue = function(){
        var val = _returnValue;
        _returnValue = undefined;
        return val;
    };

    var _setReturnValue = function(val){
        _returnValue = val;
    };

    var _getTypeDist = function(lvalue, rvalue){
        // TODO: use inheritance
        if(lvalue.type == "Object"){
            return 1;
        }
        if(lvalue.type != rvalue.type){
            return -1;
        }
        return 0;
    };

    var _resolveSelf = function(){
        var blockIndex = _blockStack.length-1;
        var result = undefined;
        while((result == undefined)&&(blockIndex >= 0)){
            result = _blockStack[blockIndex].instance;
            blockIndex--;
        }
        if(result == undefined){
            throw new ContextError(currentNode.pos, currentNode.endPos,
                        currentNode, "The 'self' keyword may only be used "
                        + "inside methods of a class'");
        }
        return result;
    };

    var _resolveVariable = function(variableName, isMemberAccess){
        var blockIndex = _blockStack.length-1;
        var result = undefined;
        if(isMemberAccess){
            var classBlock = {blockType : undefined};
            while((classBlock.blockType != "class")&&(blockIndex >= 0)){
                classBlock = _blockStack[blockIndex];
                blockIndex--;
            }
            if(classBlock.blockType == "class"){
                result = classBlock.resolveVariable(variableName);
            }
        }
        else {
            while((result == undefined)&&(blockIndex >= 0)){
                if((_blockStack[blockIndex].blockType != "class")
                    ||(_blockStack[blockIndex] == _blockStack.peek()))
                {
                    result = _blockStack[blockIndex]
                                .resolveVariable(variableName);
                }
                blockIndex--;
            }
        }
        return result;
    };

    var _resolveFunction = function(functionName, isMemberAccess){
        var blockIndex = _blockStack.length-1;
        var result = undefined;
        // TODO: overload resolution
        if(isMemberAccess){
            var classBlock = {blockType : undefined};
            while((classBlock.blockType != "class")&&(blockIndex >= 0)){
                classBlock = _blockStack[blockIndex];
                blockIndex--;
            }
            if(classBlock.blockType == "class"){
                result = classBlock.resolveFunction(functionName);
            }
        }
        else {
            while((result == undefined)&&(blockIndex >= 0)){
                if((_blockStack[blockIndex].blockType != "class")
                    ||(_blockStack[blockIndex] == _blockStack.peek()))
                {
                    result = _blockStack[blockIndex]
                            .resolveFunction(functionName);
                }
                blockIndex--;
            }
        }
        return result;
    };

    var _resolveClass = function(className){
        var blockIndex = _blockStack.length-1;
        var result = undefined;

        while((result == undefined)&&(blockIndex >= 0)){
            result = _blockStack[blockIndex].resolveClass(className);
            blockIndex--;
        }
        return result;
    };

    // -------------------------------------------------------------------------
    // -- evaluation action functions ------------------------------------------
    // -------------------------------------------------------------------------

    _actions['WhileLoop'] = function(node) {
        while(_eval(node.condition).getValue()){
            _eval(node.body);
            if(_abortBlock != undefined){
                if(_abortBlock.command == "skip"){
                    _abortBlock = undefined;
                    continue;
                }
                else if(_abortBlock.command == "break"){
                    _abortBlock = undefined;
                    break;
                }
                else if(_abortBlock.command == "return"){
                    break;
                }
            }
        }
    }

    _actions['IfStatement'] = function(node) {
        if(_eval(node.condition).getValue()){
            _eval(node.trueBody);
        }
        else{
            _eval(node.falseBody);
        }
    }

    _actions['Literal'] = function(node) {
        return node;
    }

    _actions['SelfExpression'] = function(node) {
        return _resolveSelf();
    }

    _actions['MethodCall'] = function(node) {
        _eval(node.memberAccess);
    }

    var classInstantiation = function(node, clsDecl){
        var instance = clsDecl.createInstance(node);
        instance.block.instance = instance;

        // evaluate the initialization statements
        _eval(instance.block);

        // call the initializer (if there is one)
        _blockStack.push(clsDecl.block);
        _blockStack.push(instance.block);
        try{
            var initCall = mtyParser.createFunctionCall(node.pos, node.endPos,
                                    "initializer", node.parameters);
            initCall.isMemberAccess = true;
            _eval(initCall);
        } catch(err) {
            if(err.msg != "The method 'initializer' could not be resolved."){
                throw(err);
            }
        }
        _blockStack.pop();
        _blockStack.pop();

        return instance;
    }

    _actions['FunctionCall'] = function(node) {
        var clsDecl = _resolveClass(node.functionName);
        if(clsDecl != undefined){
            return classInstantiation(node, clsDecl);
        }else{
            var funDecl = _resolveFunction(node.functionName,
                                            node.isMemberAccess);
            if(funDecl == undefined){
                switch(node.functionName){
                    case "print":
                        var param = _eval(node.parameters[0]);
                        _printfn(""+param.getValue());
                        break;
                    case "println":
                        var param = _eval(node.parameters[0]);
                        _printfn(""+param.getValue() + "\n");
                        break;
                    default:
                        var funType = node.isMemberAccess ?
                                    "method" : "function";
                        throw new ContextError(node.pos, node.endPos, node,
                            "The "+funType+" '"+node.functionName
                            +"' could not be resolved.");
                }
            }
            else{
                var contents = [];
                var argc = node.parameters ? node.parameters.length : 0;
                var parc = funDecl.parameters ? funDecl.parameters.length : 0;
                var defc = funDecl.parameters.filter(
                    function(e){return Array.isArray(e);}).length;

                if(argc != parc){
                    if(defc == 0){
                        throw new ContextError(node.pos, node.endPos,
                            node, "The function '"+node.functionName
                                +"' takes exactly "+parc+" parameters, "
                                +argc+" were given");
                    } else if((argc < (parc-defc))||(argc > parc)) {
                        throw new ContextError(node.pos, node.endPos,
                            node, "The function '"+node.functionName
                                +"' takes "+(parc-defc)+" to "+parc
                                +" parameters, "+argc+" were given");
                    }
                }

                for(var i=0; i < parc; i++){
                    if(i < argc){
                        var param = funDecl.parameters[i];
                        if(Array.isArray(param)){ param = param[0]; }
                        var arg = node.parameters[i];
                        var varaccess = mtyParser.createVariableAccess(arg.pos,
                                                            arg.endPos,
                                                            param.variableName);
                        contents.push(param);
                        contents.push(mtyParser.createAssignment(arg.pos,
                                                                arg.endPos,
                                                                varaccess, arg));
                    }
                    else{
                        var param = funDecl.parameters[i][0];
                        var assign = funDecl.parameters[i][1];
                        contents.push(param);
                        contents.push(assign);
                    }
                }
                var paramBlock = mtyParser.createBlock(funDecl.pos, funDecl.endPos,
                                                        contents, "parameters");

                _eval(paramBlock);
                // the param block is a parent block of the function body block
                // this way, the parameter declarations are visible within the
                // function body
                _blockStack.push(paramBlock);
                _eval(funDecl.body);
                _blockStack.pop();

                _abortBlock = undefined;
                return _getReturnValue();
        }
        }
    }

    /* declarations are not processed by the interpreter for now
       this may be used when a REPL is implemented
    _actions['VariableDeclaration'] = function(node) {}
    _actions['FunctionDeclaration'] = function(node) {}
    _actions['ClassDeclaration'] = function(node) {}
    */

    _actions['VariableAccess'] = function(node, lvalue) {
        var vardecl = _resolveVariable(node.variableName, node.isMemberAccess);
        if(vardecl == undefined){
            var varType = node.isMemberAccess ? "attribute" : "variable";
            throw new ContextError(node.pos, node.endPos,
                        node, "The "+varType+" '"+node.variableName
                        +"' could not be resolved.");
        }
        if(! lvalue){vardecl = vardecl.getValue(); }
        return vardecl;
    }

    _actions['Assignment'] = function(node) {
        var lvalue = _eval(node.left, true);
        var rvalue = _eval(node.right);
        if(_getTypeDist(lvalue, rvalue) < 0){
            throw new ContextError(node.pos, node.endPos,
                        node, "Type error: rhs expression type "+
                        rvalue.type + " does not match lhs type "+lvalue.type);
        }
        lvalue.value = rvalue;
    }

    _actions['CommandStatement'] = function(node) {
        switch(node.command){
            case 'return':
                if(node.argument){
                    _setReturnValue(_eval(node.argument));
                }
                _abortBlock = node;
                break;
            case 'yield': // TODO: implement
                break;
            case 'raise': // TODO: implement
                break;
            case 'skip': // node.argument always undefined
                _abortBlock = node;
                break;
            case 'break': // node.argument always undefined
                _abortBlock = node;
                break;
        }
    }

    var _checkAbortBlock = function(node){
        if((_abortBlock.command == "break")||(_abortBlock.command == "skip")){
            if((node.blockType == "function")||(node.blockType == "module")){
                throw new ContextError(node.pos, node.endPos, node,
                        "Invalid "+_abortBlock.command
                        +" statement outside loop.");
            }
        }
        else if(_abortBlock.command == "return"){
            if(node.blockType == "module"){
                throw new ContextError(node.pos, node.endPos, node,
                        "Invalid return statement outside function.");

            }
        }
    }

     _actions['Block'] = function(node) {
        _blockStack.push(node);
        var stmts = node.statements;
        for(var i = 0; i < stmts.length; i++){
            _eval(stmts[i]);
            if(_abortBlock != undefined){
                _checkAbortBlock(node);
                break;
            }
        }
        _blockStack.pop();
    }

    _actions['UnaryExpression'] = function(node) {
        switch(node.operator){
            case '-':
                break;
            case 'not':
                break;
        }
    }

    var _memberAccess = function(node, lvalue){
        var left = _eval(node.left).getValue()
        var right;
        _blockStack.push(left.block);
        node.right.isMemberAccess = true;
        right = _eval(node.right, lvalue);
        _blockStack.pop();

        return right;
    }

    _actions['BinaryExpression'] = function(node, lvalue) {
        if(node.op == "."){
            return _memberAccess(node, lvalue);
        }

        var left = _eval(node.left).getValue();
        var right = _eval(node.right).getValue();

        // result = new Expression();
        result = mtyParser.createExpression();
        switch(node.op){
            case '+':
                result.value = left + right;
                break;
            case '-':
                result.value = left - right;
                break;
            case '*':
                result.value = left * right;
                break;
            case '/':
                result.value = left / right;
                break;
            case '%':
                result.value = left % right;
                break;
            case '^':
                result.value = Math.pow(left, right);
                break;
            case '=':
                result.value = left === right;
                break;
            case '!=':
                result.value = left !== right;
                break;
            case '<':
                result.value = left < right;
                break;
            case '>':
                result.value = left > right;
                break;
            case '<=':
                result.value = left <= right;
                break;
            case '>=':
                result.value = left >= right;
                break;
        }
        return result;
    }

    // -------------------------------------------------------------------------
    // -------------------------------------------------------------------------

    this.run = function(){
        try{
            _eval(ast);
        }
        catch(err){
            if(err.constructor.name == "ContextError"){
                err.type = "ContextError";
                throw err;
            }
            else{
                err.type = "__internal__";
                if(currentNode == undefined){
                    currentNode = {
                        name : "",
                        pos : mtyParser.createPos(-1,-1),
                        endPos : mtyParser.createPos(-1,-1)
                    }
                }
                var err = new InternalError(currentNode.pos, currentNode.endPos,
                                        currentNode, err.message,
                                        mtyParser.createPos(err.lineNumber,
                                                            err.columnNumber),
                                        err.fileName);
                err.type = "InternalError";
                throw err;
            }
        }
    }
}<|endoftext|>


<commit_before>/**
 *
 * GraphQlapi
 *
 */

import React from 'react';
// import styled from 'styled-components';

import IFrame from 'react-iframe';
import Card, { CardActions, CardContent } from 'material-ui/Card';
import Button from 'material-ui/Button';

import { graphQLRoot } from 'utils/constants';

class GraphQlapi extends React.Component { // eslint-disable-line react/prefer-stateless-function
  constructor(props) {
    super(props);
    this.state = {
      showInfo: true,
    };
    this.handleGotit = this.handleGotit.bind(this);
  }

  handleGotit() {
    this.setState({
      showInfo: false,
    });
  }
  render() {
    return (

CatApp Database API

        {this.state.showInfo === false ? null :
        <Card style={{ marginBottom: 20 }}>
          <CardContent>

Welcome to the GraphQL API

You can write you own queries and submit them with

Command + Enter

Some examples are

{'{systems}'}

{'{catapp { edges { node { reactants products reactionEnergy } } }}'}

{'{systems(last: 5) { edges { node { id energy PublicationTitle keyValuePairs } } }}'}

{"Open the 'Docs' tab on the right to find a full documentation."}

Alternatively you query from the command line using
curl
:

{ `curl -XPOST http://catappdatabase.herokuapp.com/graphql --data 'query={systems(last: 10 ) {
  edges {
    node {
      energy Cifdata
          }
  }
}}' ` }

Or you can send the same query from a python script like so

{'import requests\n' +
              `requests.post(root, {'query':
              '{systems(last: 5) { edges { node { energy PublicationTitle InputFile(format: "espresso-in") } } }}
              }).json()`}

          </CardContent>
          <CardActions>
            <Button dense color="primary" onClick={this.handleGotit}>Got it! </Button>
          </CardActions>
        </Card>
        }

    );
  }
}

GraphQlapi.propTypes = {

};

export default GraphQlapi;
<commit_msg>Persist display of graphql intro with cookies<commit_after>/**
 *
 * GraphQlapi
 *
 */

import React from 'react';
import PropTypes, { instanceOf } from 'prop-types';

import IFrame from 'react-iframe';
import Card, { CardActions, CardContent } from 'material-ui/Card';
import Button from 'material-ui/Button';
import Paper from 'material-ui/Paper';
import Grid from 'material-ui/Grid';

import { withStyles } from 'material-ui/styles';
import { withCookies, Cookies } from 'react-cookie';

import { graphQLRoot } from 'utils/constants';

const styles = (theme) => ({
  button: {
    margin: theme.spacing.unit * 2.5,
  },
});

class GraphQlapi extends React.Component { // eslint-disable-line react/prefer-stateless-function
  constructor(props) {
    super(props);
    this.state = {
      graphqlShowInfo: ((this.props.cookies.get('graphqlShowInfo') || 'true') === 'true'),
    };
    this.handleGotit = this.handleGotit.bind(this);
  }

  handleGotit(value) {
    this.setState({
      graphqlShowInfo: value,
    });
    this.props.cookies.set('graphqlShowInfo', value);
  }
  render() {
    return (

        <Grid container direction="row" justify="space-between">
          <Grid item>

CatApp Database API

          </Grid>
          <Grid item>
            {this.state.graphqlShowInfo === true ? null :
            <Button className={this.props.classes.button} color="primary" onClick={() => { this.handleGotit(true); }}>Help!</Button>
        }
          </Grid>
        </Grid>
        {this.state.graphqlShowInfo === false ? null :
        <Card style={{ marginBottom: 20 }}>
          <CardContent>
            <Grid container direction="row" justify="space-between">
              <Grid item >

Welcome to the GraphQL API

              </Grid>
              <Grid item >
                <CardActions>
                  <Button color="primary" onClick={() => { this.handleGotit(false); }}>Got it! </Button>
                </CardActions>
              </Grid>
            </Grid>

You can write you own queries and submit them with

Command + Enter

Some examples are

{'{systems}'}

{'{catapp { edges { node { reactants products reactionEnergy } } }}'}

{'{systems(last: 5) { edges { node { id energy PublicationTitle keyValuePairs } } }}'}

{"Open the 'Docs' tab on the right to find a full documentation."}

Alternatively you query from the command line using
curl
:

{ `curl -XPOST http://catappdatabase.herokuapp.com/graphql --data 'query={systems(last: 10 ) {
  edges {
    node {
      energy Cifdata
          }
  }
}}' ` }

Or you can send the same query from a python script like so

{'import requests\n' +
                `requests.post(root, {'query':
              '{systems(last: 5) { edges { node { energy PublicationTitle InputFile(format: "espresso-in") } } }}
              }).json()`}

            <Grid container direction="row" justify="flex-end">
              <Grid item >
                <CardActions>
                  <Button color="primary" onClick={() => { this.handleGotit(false); }}>Got it! </Button>
                </CardActions>
              </Grid>
            </Grid>
          </CardContent>
        </Card>
        }

        <Paper>

        </Paper>

    );
  }
}

GraphQlapi.propTypes = {
  cookies: instanceOf(Cookies),
  classes: PropTypes.object,

};

export default withCookies(
  withStyles(styles, { withTheme: true })(
    GraphQlapi
  )
);
<|endoftext|>


<commit_before>/**
 * TagSpaces - universal file and folder organizer
 * Copyright (C) 2017-present TagSpaces UG (haftungsbeschraenkt)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License (version 3) as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * @flow
 */

import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import classNames from 'classnames';
import ToggleButton from '@material-ui/lab/ToggleButton';
import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
import IconButton from '@material-ui/core/IconButton';
import NewFileIcon from '@material-ui/icons/AddCircle';
import LocationsIcon from '@material-ui/icons/WorkOutline';
import TagLibraryIcon from '@material-ui/icons/LocalOfferOutlined';
import SearchIcon from '@material-ui/icons/SearchOutlined';
// import PerspectivesIcon from '@material-ui/icons/MapOutlined';
import SettingsIcon from '@material-ui/icons/Settings';
// import ThemingIcon from '@material-ui/icons/InvertColors';
// import UpgradeIcon from '@material-ui/icons/FlightTakeoff';
// import HelpIcon from '@material-ui/icons/HelpOutline';
import { withStyles } from '@material-ui/core/styles';
// import LogoIcon from '../assets/images/icon100x100.svg';
import TagLibrary from '../components/TagLibrary';
import Search from '../components/Search';
import PerspectiveManager from '../components/PerspectiveManager';
import LocationManager from '../components/LocationManager';
import HelpFeedbackPanel from '../components/HelpFeedbackPanel';
import i18n from '../services/i18n';
// import { Pro } from '../pro';
import {
  actions as AppActions,
  isSettingsDialogOpened,
  isLocationManagerPanelOpened,
  isTagLibraryPanelOpened,
  isSearchPanelOpened,
  isPerspectivesPanelOpened,
  isHelpFeedbackPanelOpened,
  isReadOnlyMode,
  getDirectoryPath
} from '../reducers/app';
import { actions as SettingsActions, isFirstRun } from '../reducers/settings';

const styles = theme => ({
  bottomToolbar: {
    textAlign: 'center',
    backgroundColor: theme.palette.background.default
  },
  buttonIcon: {
    color: '#d6d6d6' // theme.palette.text.primary
  },
  button: {
  },
  selectedButton: {
    backgroundColor: '#880E4F'
  },
});

type Props = {
  classes: Object,
  isFirstRun: boolean,
  setFirstRun: (isFirstRun: boolean) => void,
  toggleOnboardingDialog: () => void,
  toggleCreateFileDialog: () => void,
  toggleAboutDialog: () => void,
  toggleKeysDialog: () => void,
  toggleSettingsDialog: () => void,
  isSettingsDialogOpened: () => void,
  isLocationManagerPanelOpened: boolean,
  openLocationManagerPanel: () => void,
  isTagLibraryPanelOpened: boolean,
  openTagLibraryPanel: () => void,
  isSearchPanelOpened: boolean,
  openSearchPanel: () => void,
  isPerspectivesPanelOpened: boolean,
  // openPerspectivesPanel: () => void,
  isHelpFeedbackPanelOpened: boolean,
  openHelpFeedbackPanel: () => void,
  closeAllVerticalPanels: () => void,
  openFileNatively: (url: string) => void,
  openURLExternally: (url: string) => void,
  switchTheme: () => void,
  hideDrawer: () => void,
  isReadOnlyMode: boolean,
  showNotification: (message: string) => void,
  directoryPath: string
};

type State = {
  isProTeaserVisible: boolean
};

class MobileNavigation extends React.Component<Props, State> {
  state = {
    isManagementPanelVisible: true,
    isProTeaserVisible: false
  };

  toggleProTeaser = () => {
    this.setState({ isProTeaserVisible: !this.state.isProTeaserVisible });
  }

  render() {
    const {
      classes,
      isFirstRun,
      isLocationManagerPanelOpened,
      isTagLibraryPanelOpened,
      isSearchPanelOpened,
      isSettingsDialogOpened,
      isPerspectivesPanelOpened,
      isHelpFeedbackPanelOpened,
      isReadOnlyMode,
      toggleCreateFileDialog,
      toggleAboutDialog,
      toggleOnboardingDialog,
      toggleSettingsDialog,
      toggleKeysDialog,
      openLocationManagerPanel,
      openTagLibraryPanel,
      openSearchPanel,
      openHelpFeedbackPanel,
      closeAllVerticalPanels,
      switchTheme,
      showNotification,
      hideDrawer,
      openFileNatively,
      openURLExternally,
      directoryPath
    } = this.props;
    return (

          <LocationManager hideDrawer={hideDrawer} style={{ display: isLocationManagerPanelOpened ? 'block' : 'none' }} />
          {isTagLibraryPanelOpened && <TagLibrary />}
          <Search hideDrawer={hideDrawer} style={{ display: isSearchPanelOpened ? 'block' : 'none' }} />
          {isPerspectivesPanelOpened && <PerspectiveManager />}
          {isHelpFeedbackPanelOpened && <HelpFeedbackPanel
            openFileNatively={openFileNatively}
            openURLExternally={openURLExternally}
            toggleKeysDialog={toggleKeysDialog}
            toggleOnboardingDialog={toggleOnboardingDialog}
            toggleProTeaser={this.toggleProTeaser}
          />}

          <IconButton
            id="verticalNavButton"
            title={i18n.t('core:settings')}
            data-tid="settings"
            onClick={() => {
              toggleSettingsDialog();
              hideDrawer();
            }}
            style={{ marginTop: -15, marginRight: 10 }}
          >
            <SettingsIcon className={classes.buttonIcon} />
          </IconButton>
          <ToggleButtonGroup exclusive>
            <ToggleButton
              id="verticalNavButton"
              onClick={openLocationManagerPanel}
              className={
                isLocationManagerPanelOpened
                  ? classNames(classes.button, classes.selectedButton)
                  : classes.button
              }
              title={i18n.t('core:locationManager')}
              data-tid="locationManager"
            >
              <LocationsIcon className={classes.buttonIcon} />
            </ToggleButton>
            <ToggleButton
              id="verticalNavButton"
              title={i18n.t('core:tagGroupOperations')}
              data-tid="tagLibrary"
              onClick={openTagLibraryPanel}
              className={
                isTagLibraryPanelOpened
                  ? classNames(classes.button, classes.selectedButton)
                  : classes.button
              }
            >
              <TagLibraryIcon className={classes.buttonIcon} />
            </ToggleButton>
            <ToggleButton
              id="verticalNavButton"
              title={i18n.t('core:searchTitle')}
              data-tid="search"
              onClick={openSearchPanel}
              className={
                isSearchPanelOpened
                  ? classNames(classes.button, classes.selectedButton)
                  : classes.button
              }
            >
              <SearchIcon className={classes.buttonIcon} />
            </ToggleButton>
          </ToggleButtonGroup>
          <IconButton
            id="verticalNavButton"
            onClick={() => {
              if (isReadOnlyMode || !directoryPath) {
                showNotification('You are in read-only mode or there is no opened location');
              } else {
                toggleCreateFileDialog();
                hideDrawer();
              }
            }}
            style={{ marginTop: -15, marginLeft: 10 }}
            title={i18n.t('core:createFileTitle')}
            data-tid="locationManager"
          >
            <NewFileIcon color="primary" />
          </IconButton>

    );
  }
}

function mapStateToProps(state) {
  return {
    isFirstRun: isFirstRun(state),
    isSettingsDialogOpened: isSettingsDialogOpened(state),
    isLocationManagerPanelOpened: isLocationManagerPanelOpened(state),
    isTagLibraryPanelOpened: isTagLibraryPanelOpened(state),
    isSearchPanelOpened: isSearchPanelOpened(state),
    isPerspectivesPanelOpened: isPerspectivesPanelOpened(state),
    isHelpFeedbackPanelOpened: isHelpFeedbackPanelOpened(state),
    isReadOnlyMode: isReadOnlyMode(state),
    directoryPath: getDirectoryPath(state),
  };
}

function mapActionCreatorsToProps(dispatch) {
  return bindActionCreators(
    {
      toggleCreateFileDialog: AppActions.toggleCreateFileDialog,
      toggleOnboardingDialog: AppActions.toggleOnboardingDialog,
      toggleSettingsDialog: AppActions.toggleSettingsDialog,
      toggleAboutDialog: AppActions.toggleAboutDialog,
      toggleKeysDialog: AppActions.toggleKeysDialog,
      openLocationManagerPanel: AppActions.openLocationManagerPanel,
      openTagLibraryPanel: AppActions.openTagLibraryPanel,
      openSearchPanel: AppActions.openSearchPanel,
      openPerspectivesPanel: AppActions.openPerspectivesPanel,
      openHelpFeedbackPanel: AppActions.openHelpFeedbackPanel,
      openFileNatively: AppActions.openFileNatively,
      openURLExternally: AppActions.openURLExternally,
      showNotification: AppActions.showNotification,
      closeAllVerticalPanels: AppActions.closeAllVerticalPanels,
      switchTheme: SettingsActions.switchTheme,
      setFirstRun: SettingsActions.setFirstRun,
    },
    dispatch
  );
}

export default connect(
  mapStateToProps,
  mapActionCreatorsToProps
)(withStyles(styles)(MobileNavigation));
<commit_msg>style: prettier<commit_after>/**
 * TagSpaces - universal file and folder organizer
 * Copyright (C) 2017-present TagSpaces UG (haftungsbeschraenkt)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License (version 3) as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * @flow
 */

import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import classNames from 'classnames';
import ToggleButton from '@material-ui/lab/ToggleButton';
import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
import IconButton from '@material-ui/core/IconButton';
import NewFileIcon from '@material-ui/icons/AddCircle';
import LocationsIcon from '@material-ui/icons/WorkOutline';
import TagLibraryIcon from '@material-ui/icons/LocalOfferOutlined';
import SearchIcon from '@material-ui/icons/SearchOutlined';
// import PerspectivesIcon from '@material-ui/icons/MapOutlined';
import SettingsIcon from '@material-ui/icons/Settings';
// import ThemingIcon from '@material-ui/icons/InvertColors';
// import UpgradeIcon from '@material-ui/icons/FlightTakeoff';
// import HelpIcon from '@material-ui/icons/HelpOutline';
import { withStyles } from '@material-ui/core/styles';
// import LogoIcon from '../assets/images/icon100x100.svg';
import TagLibrary from '../components/TagLibrary';
import Search from '../components/Search';
import PerspectiveManager from '../components/PerspectiveManager';
import LocationManager from '../components/LocationManager';
import HelpFeedbackPanel from '../components/HelpFeedbackPanel';
import i18n from '../services/i18n';
// import { Pro } from '../pro';
import {
  actions as AppActions,
  isSettingsDialogOpened,
  isLocationManagerPanelOpened,
  isTagLibraryPanelOpened,
  isSearchPanelOpened,
  isPerspectivesPanelOpened,
  isHelpFeedbackPanelOpened,
  isReadOnlyMode,
  getDirectoryPath
} from '../reducers/app';
import { actions as SettingsActions, isFirstRun } from '../reducers/settings';

const styles = theme => ({
  bottomToolbar: {
    textAlign: 'center',
    backgroundColor: theme.palette.background.default
  },
  buttonIcon: {
    color: '#d6d6d6' // theme.palette.text.primary
  },
  button: {},
  selectedButton: {
    backgroundColor: '#880E4F'
  }
});

type Props = {
  classes: Object,
  isFirstRun: boolean,
  setFirstRun: (isFirstRun: boolean) => void,
  toggleOnboardingDialog: () => void,
  toggleCreateFileDialog: () => void,
  toggleAboutDialog: () => void,
  toggleKeysDialog: () => void,
  toggleSettingsDialog: () => void,
  isSettingsDialogOpened: () => void,
  isLocationManagerPanelOpened: boolean,
  openLocationManagerPanel: () => void,
  isTagLibraryPanelOpened: boolean,
  openTagLibraryPanel: () => void,
  isSearchPanelOpened: boolean,
  openSearchPanel: () => void,
  isPerspectivesPanelOpened: boolean,
  // openPerspectivesPanel: () => void,
  isHelpFeedbackPanelOpened: boolean,
  openHelpFeedbackPanel: () => void,
  closeAllVerticalPanels: () => void,
  openFileNatively: (url: string) => void,
  openURLExternally: (url: string) => void,
  switchTheme: () => void,
  hideDrawer: () => void,
  isReadOnlyMode: boolean,
  showNotification: (message: string) => void,
  directoryPath: string
};

type State = {
  isProTeaserVisible: boolean
};

class MobileNavigation extends React.Component<Props, State> {
  state = {
    isManagementPanelVisible: true,
    isProTeaserVisible: false
  };

  toggleProTeaser = () => {
    this.setState({ isProTeaserVisible: !this.state.isProTeaserVisible });
  };

  render() {
    const {
      classes,
      isFirstRun,
      isLocationManagerPanelOpened,
      isTagLibraryPanelOpened,
      isSearchPanelOpened,
      isSettingsDialogOpened,
      isPerspectivesPanelOpened,
      isHelpFeedbackPanelOpened,
      isReadOnlyMode,
      toggleCreateFileDialog,
      toggleAboutDialog,
      toggleOnboardingDialog,
      toggleSettingsDialog,
      toggleKeysDialog,
      openLocationManagerPanel,
      openTagLibraryPanel,
      openSearchPanel,
      openHelpFeedbackPanel,
      closeAllVerticalPanels,
      switchTheme,
      showNotification,
      hideDrawer,
      openFileNatively,
      openURLExternally,
      directoryPath
    } = this.props;
    return (

          <LocationManager
            hideDrawer={hideDrawer}
            style={{
              display: isLocationManagerPanelOpened ? 'block' : 'none'
            }}
          />
          {isTagLibraryPanelOpened && <TagLibrary />}
          <Search
            hideDrawer={hideDrawer}
            style={{ display: isSearchPanelOpened ? 'block' : 'none' }}
          />
          {isPerspectivesPanelOpened && <PerspectiveManager />}
          {isHelpFeedbackPanelOpened && (
            <HelpFeedbackPanel
              openFileNatively={openFileNatively}
              openURLExternally={openURLExternally}
              toggleKeysDialog={toggleKeysDialog}
              toggleOnboardingDialog={toggleOnboardingDialog}
              toggleProTeaser={this.toggleProTeaser}
            />
          )}

          <IconButton
            id="verticalNavButton"
            title={i18n.t('core:settings')}
            data-tid="settings"
            onClick={() => {
              toggleSettingsDialog();
              hideDrawer();
            }}
            style={{ marginTop: -15, marginRight: 10 }}
          >
            <SettingsIcon className={classes.buttonIcon} />
          </IconButton>
          <ToggleButtonGroup exclusive>
            <ToggleButton
              id="verticalNavButton"
              onClick={openLocationManagerPanel}
              className={
                isLocationManagerPanelOpened
                  ? classNames(classes.button, classes.selectedButton)
                  : classes.button
              }
              title={i18n.t('core:locationManager')}
              data-tid="locationManager"
            >
              <LocationsIcon className={classes.buttonIcon} />
            </ToggleButton>
            <ToggleButton
              id="verticalNavButton"
              title={i18n.t('core:tagGroupOperations')}
              data-tid="tagLibrary"
              onClick={openTagLibraryPanel}
              className={
                isTagLibraryPanelOpened
                  ? classNames(classes.button, classes.selectedButton)
                  : classes.button
              }
            >
              <TagLibraryIcon className={classes.buttonIcon} />
            </ToggleButton>
            <ToggleButton
              id="verticalNavButton"
              title={i18n.t('core:searchTitle')}
              data-tid="search"
              onClick={openSearchPanel}
              className={
                isSearchPanelOpened
                  ? classNames(classes.button, classes.selectedButton)
                  : classes.button
              }
            >
              <SearchIcon className={classes.buttonIcon} />
            </ToggleButton>
          </ToggleButtonGroup>
          <IconButton
            id="verticalNavButton"
            onClick={() => {
              if (isReadOnlyMode || !directoryPath) {
                showNotification(
                  'You are in read-only mode or there is no opened location'
                );
              } else {
                toggleCreateFileDialog();
                hideDrawer();
              }
            }}
            style={{ marginTop: -15, marginLeft: 10 }}
            title={i18n.t('core:createFileTitle')}
            data-tid="locationManager"
          >
            <NewFileIcon color="primary" />
          </IconButton>

    );
  }
}

function mapStateToProps(state) {
  return {
    isFirstRun: isFirstRun(state),
    isSettingsDialogOpened: isSettingsDialogOpened(state),
    isLocationManagerPanelOpened: isLocationManagerPanelOpened(state),
    isTagLibraryPanelOpened: isTagLibraryPanelOpened(state),
    isSearchPanelOpened: isSearchPanelOpened(state),
    isPerspectivesPanelOpened: isPerspectivesPanelOpened(state),
    isHelpFeedbackPanelOpened: isHelpFeedbackPanelOpened(state),
    isReadOnlyMode: isReadOnlyMode(state),
    directoryPath: getDirectoryPath(state)
  };
}

function mapActionCreatorsToProps(dispatch) {
  return bindActionCreators(
    {
      toggleCreateFileDialog: AppActions.toggleCreateFileDialog,
      toggleOnboardingDialog: AppActions.toggleOnboardingDialog,
      toggleSettingsDialog: AppActions.toggleSettingsDialog,
      toggleAboutDialog: AppActions.toggleAboutDialog,
      toggleKeysDialog: AppActions.toggleKeysDialog,
      openLocationManagerPanel: AppActions.openLocationManagerPanel,
      openTagLibraryPanel: AppActions.openTagLibraryPanel,
      openSearchPanel: AppActions.openSearchPanel,
      openPerspectivesPanel: AppActions.openPerspectivesPanel,
      openHelpFeedbackPanel: AppActions.openHelpFeedbackPanel,
      openFileNatively: AppActions.openFileNatively,
      openURLExternally: AppActions.openURLExternally,
      showNotification: AppActions.showNotification,
      closeAllVerticalPanels: AppActions.closeAllVerticalPanels,
      switchTheme: SettingsActions.switchTheme,
      setFirstRun: SettingsActions.setFirstRun
    },
    dispatch
  );
}

export default connect(
  mapStateToProps,
  mapActionCreatorsToProps
)(withStyles(styles)(MobileNavigation));
<|endoftext|>


<commit_before>"use strict";

var React = require('react');

var config = require('../../configuration');
var log = require('../../logger');
var Blink1Service = require('../../server/blink1Service');
var PatternsService = require('../../server/patternsService');

var ButtonToolbar = require('react-bootstrap').ButtonToolbar;
//var MenuItem = require('react-bootstrap').MenuItem;

var BigButton = require('./bigButton');

var buttonsUserDefault = [
    { name: "Available", type: "color", color: "#00FF00", ledn: 0 },
    { name: "Busy", type: "color", color: "#ffFF00", ledn: 0},
    { name: "Away", type: "color", color: "#ff0000", ledn: 0 },
    { name: "Meeting", type: "color", color: "#00000ff", ledn: 0 }
];

var BigButtonSet = React.createClass({
    getInitialState: function() {
        var buttonsUser = config.readSettings('bigButtons');
        if( !buttonsUser ) {
            buttonsUser = buttonsUserDefault;
        }
        return {
            buttonsSys: [
                { name: "Color Cycle", type: "sys" },
                { name: "Mood Light", type: "sys" },
                { name: "Strobe Light", type: "sys" },
                { name: "White", type: "sys" },
                { name: "Off", type: "sys" }
            ],
            buttonsUser: buttonsUser
        };
    },
    saveButtons: function(buttonsUser) {
        this.setState( {buttonsUser: buttonsUser });
        config.saveSettings("bigButtons", buttonsUser);
    },
    addBigButton: function() { // FIXME: this is hacky
        var newbut = {
            name: "Big Button "+this.state.buttonsUser.length,
            type: "color",
            color: Blink1Service.getCurrentColor().toHexString(),
            ledn: Blink1Service.getCurrentLedN()
        };
        this.state.buttonsUser.push( newbut );
        this.saveButtons( this.state.buttonsUser );
    },
    onEdit: function(cmd, idx, arg) {
        console.log('onEdit:', cmd, idx, arg);
        if( cmd === 'delete' ) {
            delete this.state.buttonsUser[ idx ];
        }
        else if( cmd === 'moveleft') {
            if( idx > 0 ) {
                var tmpbutton = this.state.buttonsUser[idx-1];
                this.state.buttonsUser[idx-1] = this.state.buttonsUser[idx];
                this.state.buttonsUser[idx] = tmpbutton;
            }
        }
        else if( cmd === 'setcolor') {
            this.state.buttonsUser[idx].type = 'color';
            this.state.buttonsUser[idx].color = Blink1Service.getCurrentColor().toHexString();
            this.state.buttonsUser[idx].ledn = Blink1Service.getCurrentLedN();
        }
        else if( cmd === 'setpattern') {
            this.state.buttonsUser[idx].type = 'pattern';
            this.state.buttonsUser[idx].color = 'grey';
            this.state.buttonsUser[idx].patternId = arg; // PatternsService.getPlayingPatternId();
            // if( this.state.buttonsUser[idx].name === 'Big Button' ) {
            //     this.state.buttonsUser[idx].name = pattern.name;
            // }
        }
        else if( cmd === 'rename' ) {
            this.state.buttonsUser[idx].name = arg;
        }
        this.saveButtons( this.state.buttonsUser );
    },
    // internal function used by differnt kinds of buttons
    setBlink1Color: function(color, ledn) {
        console.log("BigButtonSet.setBlink1Color:",color);
        ledn = ledn || 0; // 0 means all
        Blink1Service.fadeToColor( 100, color, ledn );  // FIXME: millis
    },
    playPattern: function(patternid) {
        PatternsService.playPattern( patternid );
    },

	playBigButton: function(buttontype, buttonindex) {
		console.log("playBigButton:", buttontype, buttonindex);
        var button = this.state.buttonsUser[buttonindex];
		if( buttontype === 'sys' ) {
			button = this.state.buttonsSys[buttonindex];
			if( button.name === "White" ) {
				this.setBlink1Color( "#FFFFFF" );
			}
			else if( button.name === "Off" ) {
                PatternsService.stopAllPatterns();
                Blink1Service.off();
			}
            else if( button.name === "Color Cycle" ) {
                Blink1Service.colorCycleStart();
            }
            else if( button.name === "Strobe Light" ) {
                PatternsService.playPattern( '~blink-white-0' );
            }
		}
		else if( buttontype === 'color' ) {
			this.setBlink1Color( button.color, button.ledn );
		}
        else if( buttontype === 'pattern' ) {
            this.playPattern( button.patternId );
        }
        log.addEvent({type:'trigger', source:'button', id:button.name} );
	},

    render: function() {
        var patterns = PatternsService.getAllPatterns();
        var createBigButtonSys = function(button, index) { // FIXME: understand bind()
            return (
                <BigButton key={index} name={button.name} type='sys'
                    onClick={this.playBigButton.bind(null, 'sys', index)} idx={index} />
            );
        };
        var createBigButtonUser = function(button, index) { // FIXME: understand bind()
            return (
                <BigButton key={index} idx={index} name={button.name} type={button.type}
                    color={button.color} patterns={patterns}
                    onClick={this.playBigButton.bind(null, button.type, index)}
                    onEdit={this.onEdit} />
            );
        };
        return (

                <ButtonToolbar style={{padding: 10}}>
                    {this.state.buttonsSys.map(createBigButtonSys, this)}
                </ButtonToolbar>

                    <ButtonToolbar style={{width:1500}} ref="btbar">
                        {this.state.buttonsUser.map(createBigButtonUser, this)}
                        <BigButton key="add" name="add button" type="sys" onClick={this.addBigButton}  />
                    </ButtonToolbar>

        );
    }
});

module.exports = BigButtonSet;
<commit_msg>removed console log msgs<commit_after>"use strict";

var React = require('react');

var config = require('../../configuration');
var log = require('../../logger');
var Blink1Service = require('../../server/blink1Service');
var PatternsService = require('../../server/patternsService');

var ButtonToolbar = require('react-bootstrap').ButtonToolbar;
//var MenuItem = require('react-bootstrap').MenuItem;

var BigButton = require('./bigButton');

var buttonsUserDefault = [
    { name: "Available", type: "color", color: "#00FF00", ledn: 0 },
    { name: "Busy", type: "color", color: "#ffFF00", ledn: 0},
    { name: "Away", type: "color", color: "#ff0000", ledn: 0 },
    { name: "Meeting", type: "color", color: "#00000ff", ledn: 0 }
];

var BigButtonSet = React.createClass({
    getInitialState: function() {
        var buttonsUser = config.readSettings('bigButtons');
        if( !buttonsUser ) {
            buttonsUser = buttonsUserDefault;
        }
        return {
            buttonsSys: [
                { name: "Color Cycle", type: "sys" },
                { name: "Mood Light", type: "sys" },
                { name: "Strobe Light", type: "sys" },
                { name: "White", type: "sys" },
                { name: "Off", type: "sys" }
            ],
            buttonsUser: buttonsUser
        };
    },
    saveButtons: function(buttonsUser) {
        this.setState( {buttonsUser: buttonsUser });
        config.saveSettings("bigButtons", buttonsUser);
    },
    addBigButton: function() { // FIXME: this is hacky
        var newbut = {
            name: "Big Button "+this.state.buttonsUser.length,
            type: "color",
            color: Blink1Service.getCurrentColor().toHexString(),
            ledn: Blink1Service.getCurrentLedN()
        };
        this.state.buttonsUser.push( newbut );
        this.saveButtons( this.state.buttonsUser );
    },
    onEdit: function(cmd, idx, arg) {
        // console.log('onEdit:', cmd, idx, arg);
        if( cmd === 'delete' ) {
            delete this.state.buttonsUser[ idx ];
        }
        else if( cmd === 'moveleft') {
            if( idx > 0 ) {
                var tmpbutton = this.state.buttonsUser[idx-1];
                this.state.buttonsUser[idx-1] = this.state.buttonsUser[idx];
                this.state.buttonsUser[idx] = tmpbutton;
            }
        }
        else if( cmd === 'setcolor') {
            this.state.buttonsUser[idx].type = 'color';
            this.state.buttonsUser[idx].color = Blink1Service.getCurrentColor().toHexString();
            this.state.buttonsUser[idx].ledn = Blink1Service.getCurrentLedN();
        }
        else if( cmd === 'setpattern') {
            this.state.buttonsUser[idx].type = 'pattern';
            this.state.buttonsUser[idx].color = 'grey';
            this.state.buttonsUser[idx].patternId = arg; // PatternsService.getPlayingPatternId();
            // if( this.state.buttonsUser[idx].name === 'Big Button' ) {
            //     this.state.buttonsUser[idx].name = pattern.name;
            // }
        }
        else if( cmd === 'rename' ) {
            this.state.buttonsUser[idx].name = arg;
        }
        this.saveButtons( this.state.buttonsUser );
    },
    // internal function used by differnt kinds of buttons
    setBlink1Color: function(color, ledn) {
        // console.log("BigButtonSet.setBlink1Color:",color);
        ledn = ledn || 0; // 0 means all
        Blink1Service.fadeToColor( 100, color, ledn );  // FIXME: millis
    },
    playPattern: function(patternid) {
        PatternsService.playPattern( patternid );
    },

	playBigButton: function(buttontype, buttonindex) {
		// console.log("playBigButton:", buttontype, buttonindex);
        var button = this.state.buttonsUser[buttonindex];
		if( buttontype === 'sys' ) {
			button = this.state.buttonsSys[buttonindex];
			if( button.name === "White" ) {
				this.setBlink1Color( "#FFFFFF" );
			}
			else if( button.name === "Off" ) {
                PatternsService.stopAllPatterns();
                Blink1Service.off();
			}
            else if( button.name === "Color Cycle" ) {
                Blink1Service.colorCycleStart();
            }
            else if( button.name === "Strobe Light" ) {
                PatternsService.playPattern( '~blink-white-0' );
            }
		}
		else if( buttontype === 'color' ) {
			this.setBlink1Color( button.color, button.ledn );
		}
        else if( buttontype === 'pattern' ) {
            this.playPattern( button.patternId );
        }
        log.addEvent({type:'trigger', source:'button', id:button.name} );
	},

    render: function() {
        var patterns = PatternsService.getAllPatterns();
        var createBigButtonSys = function(button, index) { // FIXME: understand bind()
            return (
                <BigButton key={index} name={button.name} type='sys'
                    onClick={this.playBigButton.bind(null, 'sys', index)} idx={index} />
            );
        };
        var createBigButtonUser = function(button, index) { // FIXME: understand bind()
            return (
                <BigButton key={index} idx={index} name={button.name} type={button.type}
                    color={button.color} patterns={patterns}
                    onClick={this.playBigButton.bind(null, button.type, index)}
                    onEdit={this.onEdit} />
            );
        };
        return (

                <ButtonToolbar style={{padding: 10}}>
                    {this.state.buttonsSys.map(createBigButtonSys, this)}
                </ButtonToolbar>

                    <ButtonToolbar style={{width:1500}} ref="btbar">
                        {this.state.buttonsUser.map(createBigButtonUser, this)}
                        <BigButton key="add" name="add button" type="sys" onClick={this.addBigButton}  />
                    </ButtonToolbar>

        );
    }
});

module.exports = BigButtonSet;
<|endoftext|>


<commit_before>/*
 *
 * Commande reducer
 *
 */
import update from 'react-addons-update';
import c from './constants';
import cF from 'containers/AdminFournisseur/constants';
import cE from 'containers/CommandeEdit/constants';
import { normalize, arrayOf } from 'normalizr';
import { schemas } from './schemas';
import merge from 'lodash/merge';
import omit from 'lodash/omit';
import assign from 'lodash/assign';
import includes from 'lodash/includes';
import uniq from 'lodash/uniq';

const initialState = {
  pending: false,
  datas: {
    entities: {},
    result: [],
  },
  error: null,
};

const ajouter = (state, action) => {
  const contenu = state.datas.entities.commandeContenu[action.contenuId];

  return update(state, {
    datas: {
      entities: {
        commandeContenu: {
          [action.contenuId]: {
            quantite: { $set: contenu.quantite + action.quantite },
          },
        },
      },
    },
  });
};

const annuleCommandeUtilisateur = (state, commandeUtilisateurId, cdeId) => {
  const {
    commandeUtilisateurs,
    commandeContenus,
    commandes,
  } = state.datas.entities;

  const contenusRestants = Object.keys(commandeContenus)
    .filter(id => commandeUtilisateurs[id] && !includes(commandeUtilisateurs[id].contenus, id))
    .reduce((memo, id) => ({ [id]: commandeContenus[id] }), {});

  const commandeUtilisateursRestants = Object.keys(commandeUtilisateurs)
    .filter(id => id !== commandeUtilisateurId)
    .reduce((memo, id) => ({ [id]: commandeUtilisateurs[id] }), {});

  const commandeCommandeUtilisateursRestants = commandes[cdeId].commandeUtilisateurs.filter(
    id => id !== commandeUtilisateurId,
  );

  return update(state, {
    datas: {
      entities: {
        commandeUtilisateurs: { $set: commandeUtilisateursRestants },
        commandeContenus: { $set: contenusRestants },
        commandes: {
          [cdeId]: {
            commandeUtilisateurs: {
              $set: commandeCommandeUtilisateursRestants,
            },
          },
        },
      },
    },
  });
};

const supprimeCommandeContenusFournisseur = (state, fournisseurId, commandeId) => {
  const {
    commandeContenus,
    offres,
    produits,
    commandeUtilisateurs,
  } = state.datas.entities;

  const commandeContenusASupprimerIds = Object.keys(commandeContenus)
    .filter(
      id =>
        commandeContenus[id].commandeId === commandeId &&
        produits[offres[commandeContenus[id].offreId].produitId].fournisseurId === fournisseurId,
    );

  const commandeUtilisateursModifiee = uniq( // il peut y a voir plusieurs contenus pour une meme commandeUtilisateur
    commandeContenusASupprimerIds.map(ccId => commandeContenus[ccId].commandeUtilisateurId),
  ).reduce(
    (memo, cuId) => ({
      ...memo,
      [cuId]: {
        ...commandeUtilisateurs[cuId],
        contenus: commandeUtilisateurs[cuId].contenus.filter(
          id => !includes(commandeContenusASupprimerIds, id),
        ),
      },
    }),
    {},
  );

  const commandeContenusModifiee = Object.keys(commandeContenus)
    .filter(id => !includes(commandeContenusASupprimerIds, id))
    .reduce(
      (memo, id) => ({
        ...memo,
        [id]: commandeContenus[id],
      }),
      {},
    );

  return update(state, {
    datas: {
      entities: {
        commandeContenus: {
          $set: { ...commandeContenus, ...commandeContenusModifiee },
        },
        commandeUtilisateurs: {
          $set: { ...commandeUtilisateurs, ...commandeUtilisateursModifiee },
        },
      },
    },
  });
};

const supprimeContenu = (state, contenu) => {
  const { commandeUtilisateurs, commandeContenus } = state.datas.entities;
  const contenusRestants = commandeUtilisateurs[contenu.commandeUtilisateurId].contenus.filter(
    cont => cont !== contenu.id,
  ); // eslint-disable-line
  const commandeContenusRestants = Object.keys(commandeContenus).reduce((memo, cont) => {
    const aIns = cont.id !== contenu.id ? { [contenu.id]: contenu } : {};
    return { ...memo, aIns };
  }, {});
  return update(state, {
    datas: {
      entities: {
        commandeUtilisateurs: {
          [contenu.commandeUtilisateurId]: {
            contenus: { $set: contenusRestants },
          },
          commandeContenus: { $set: commandeContenusRestants },
        },
      },
    },
  });
};

// const majNouvelAchat = (state, commandeContenu) => {
//   const majCu = update(
//     state,
//     { datas:
//       { entities:
//         { commandeUtilisateurs:
//           { [commandeContenu.commandeUtilisateurId]:
//             { contenus: { $push: [commandeContenu] },
//           },
//         },
//       },
//     },
//     },
//   );
//   // const produit = state.datas.entities.produits[state.datas.entities.offres[commandeContenu.offreId].produitId];
//   // const nStock = produit.stock - commandeContenu.quantite;
//   // return update(majCu, { datas: { entities: { produits: { [produit.id]: { stock: { $set: nStock } } } } } });
//   return majCu;
// };

function commandeReducer(state = initialState, action) {
  switch (action.type) {
    case c.ASYNC_LOAD_FOURNISSEURS_SUCCESS: {
      const datas = normalize(action.datas.fournisseurs, arrayOf(schemas.FOURNISSEURS));
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
          result: { $push: datas.result },
        },
        pending: { $set: false },
      });
    }
    case c.ASYNC_LOAD_OFFRES_SUCCESS: {
      const datas = normalize(action.datas.offre_produits, arrayOf(schemas.OFFRES));
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
          result: { $push: datas.result },
        },
        pending: { $set: false },
      });
    }
    case c.ASYNC_LOAD_USER_COMMANDES_SUCCESS:
    case c.ASYNC_LOAD_COMMANDES_SUCCESS: {
      const datas = normalize(action.datas.commandes, arrayOf(schemas.COMMANDES));
      const defaults = {
        commandes: {},
        commandeContenus: {},
        commandeUtilisateurs: {},
        livraisons: {},
        fournisseurs: {},
      };
      return update(state, {
        datas: {
          entities: {
            $set: merge(state.datas.entities, assign(defaults, datas.entities)),
          },
          result: { $push: datas.result },
        },
        pending: { $set: false },
      });
    }
    case cE.ASYNC_SAUVEGARDER_SUCCESS: {
      const datas = normalize(action.datas, schemas.COMMANDE_UTILISATEURS);
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
          result: { $push: [datas.result] },
        },
        pending: { $set: false },
      });
    }

    case cE.ASYNC_ANNULER_SUCCESS: {
      const { commandeId, id } = action.req.datas;
      return annuleCommandeUtilisateur(state, id, commandeId);
    }

    case c.ASYNC_CREATE_COMMANDE_SUCCESS:
    case c.ASYNC_LOAD_COMMANDE_SUCCESS: {
      const datas = normalize(action.datas, schemas.COMMANDES);
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
          result: { $push: [datas.result] },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_DELETE_COMMANDE_SUCCESS: {
      const { id } = action.req.datas;
      const { commandes } = state.datas.entities;
      const commandesRestantes = Object.keys(commandes)
        .reduce((memo, key) => key !== id ? { ...memo, [key]: commandes[key] } : memo, {});

      return update(state, {
        datas: { entities: { commandes: { $set: commandesRestantes } } },
      });
    }

    case c.ASYNC_LOAD_RELAIS_SUCCESS: {
      const datas = normalize(action.datas.relais, arrayOf(schemas.RELAIS));
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_SAVE_PRODUIT_SUCCESS: {
      const datas = normalize(action.datas, schemas.PRODUITS);

      return update(state, {
        datas: {
          entities: {
            produits: {
              [action.datas.id]: {
                $set: datas.entities.produits[action.datas.id],
              },
            },
            pending: { $set: false },
          },
        },
      });
    }

    case c.ASYNC_SAVE_OFFRE_SUCCESS: {
      const datas = normalize(action.datas, schemas.OFFRES);

      return update(state, {
        datas: {
          entities: {
            offres: {
              [action.datas.id]: {
                $set: datas.entities.offres[action.datas.id],
              },
            },
            pending: { $set: false },
          },
        },
      });
    }

    case c.ASYNC_IMPORTE_OFFRES_SUCCESS: {
      const datas = normalize(action.datas.offres, schemas.OFFRES);
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_LOAD_TYPES_PRODUITS_SUCCESS: {
      const datas = normalize(action.datas.type_produits, arrayOf(schemas.TYPES_PRODUITS));
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_LOAD_FOURNISSEUR_SUCCESS:
    case cF.ASYNC_LOAD_FOURNISSEUR_SUCCESS: {
      const datas = normalize(action.datas, schemas.FOURNISSEURS);
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_MODIFIER_COMMANDE_CONTENU_SUCCESS: {
      const datas = normalize(action.datas, schemas.COMMANDE_CONTENUS);
      return update(state, {
        datas: {
          entities: {
            commandeContenus: {
              [action.datas.id]: {
                $set: datas.entities.commandeContenus[action.datas.id],
              },
            },
          },
        },
      });
    }

    case c.ASYNC_SUPPRIMER_COMMANDE_CONTENUS_FOURNISSEUR_SUCCESS: {
      const { fournisseurId, commandeId } = action.req.datas;
      return supprimeCommandeContenusFournisseur(state, fournisseurId, commandeId);
    }

    case c.ASYNC_PAYE_COMMANDE_UTILISATEUR_SUCCESS:
    case c.ASYNC_LIVRE_COMMANDE_UTILISATEUR_SUCCESS: {
      const datas = normalize(action.datas, schemas.COMMANDE_UTILISATEURS);
      return update(state, {
        datas: {
          entities: {
            commandeUtilisateurs: {
              [action.datas.id]: {
                $set: datas.entities.commandeUtilisateurs[action.datas.id],
              },
            },
          },
        },
      });
    }

    case c.AJOUTER:
      return ajouter(state, action);
    case c.NOUVEL_ACHAT: {
      const nCommandeContenus = {
        ...state.datas.entities.commandeContenus,
        [action.datas.id]: action.datas,
      };
      return update(state, {
        datas: { entities: { commandeContenus: { $set: nCommandeContenus } } },
      });
    }
    case c.SUPPRESSION_ACHAT: {
      const nCommandeContenus = omit(state.datas.entities.commandeContenus, action.datas.id);
      return update(state, {
        datas: { entities: { commandeContenus: { $set: nCommandeContenus } } },
      });
    }
    case c.MODIF_ACHAT: {
      return update(state, {
        datas: {
          entities: {
            commandeContenus: {
              $set: {
                ...state.datas.entities.commandeContenus,
                [action.datas.id]: action.datas,
              },
            },
          },
        },
      });
    }

    case c.ASYNC_SUPPRIMER_COMMANDE_CONTENU_SUCCESS:
      return supprimeContenu(state, action.req.datas);

    case c.ASYNC_LOAD_UTILISATEURS_SUCCESS: {
      const datas = normalize(action.datas.utilisateurs, arrayOf(schemas.UTILISATEURS));
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_LOAD_COMMANDE_UTILISATEURS_SUCCESS: {
      const datas = normalize(action.datas.commande_utilisateurs, arrayOf(schemas.COMMANDE_UTILISATEURS));
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_SAVE_UTILISATEUR_SUCCESS: {
      const datas = normalize(action.datas, schemas.UTILISATEURS);

      return update(state, {
        datas: {
          entities: {
            utilisateurs: {
              [action.datas.id]: {
                $set: datas.entities.utilisateurs[action.datas.id],
              },
            },
            pending: { $set: false },
          },
        },
      });
    }

    case 'ws/NOUVELLE_COMMANDE_UTILISATEUR': {
      const nCu = action.datas;
      nCu.contenus = [];
      return update(state, {
        datas: {
          entities: { commandeUtilisateurs: { [nCu.id]: { $set: nCu } } },
        },
      });
    }

    // case 'ws/NOUVEL_ACHAT': // websocket
    //   return majNouvelAchat(state, action.datas);
    case 'ws/OFFRE_MODIF_STOCK':
      return update(state, {
        datas: {
          entities: {
            offres: {
              [action.datas.id]: { stock: { $set: action.datas.stock } },
            },
          },
        },
      });
    default:
      return state;
  }
}

export default commandeReducer;
<commit_msg>refact ws<commit_after>/*
 *
 * Commande reducer
 *
 */
import update from 'react-addons-update';
import c from './constants';
import cF from 'containers/AdminFournisseur/constants';
import cE from 'containers/CommandeEdit/constants';
import { normalize, arrayOf } from 'normalizr';
import { schemas } from './schemas';
import merge from 'lodash/merge';
import omit from 'lodash/omit';
import assign from 'lodash/assign';
import includes from 'lodash/includes';
import uniq from 'lodash/uniq';

const initialState = {
  pending: false,
  datas: {
    entities: {},
    result: [],
  },
  error: null,
};

const ajouter = (state, action) => {
  const contenu = state.datas.entities.commandeContenu[action.contenuId];

  return update(state, {
    datas: {
      entities: {
        commandeContenu: {
          [action.contenuId]: {
            quantite: { $set: contenu.quantite + action.quantite },
          },
        },
      },
    },
  });
};

const annuleCommandeUtilisateur = (state, commandeUtilisateurId, cdeId) => {
  const {
    commandeUtilisateurs,
    commandeContenus,
    commandes,
  } = state.datas.entities;

  const contenusRestants = Object.keys(commandeContenus)
    .filter(id => commandeUtilisateurs[id] && !includes(commandeUtilisateurs[id].contenus, id))
    .reduce((memo, id) => ({ [id]: commandeContenus[id] }), {});

  const commandeUtilisateursRestants = Object.keys(commandeUtilisateurs)
    .filter(id => id !== commandeUtilisateurId)
    .reduce((memo, id) => ({ [id]: commandeUtilisateurs[id] }), {});

  const commandeCommandeUtilisateursRestants = commandes[cdeId].commandeUtilisateurs.filter(
    id => id !== commandeUtilisateurId
  );

  return update(state, {
    datas: {
      entities: {
        commandeUtilisateurs: { $set: commandeUtilisateursRestants },
        commandeContenus: { $set: contenusRestants },
        commandes: {
          [cdeId]: {
            commandeUtilisateurs: {
              $set: commandeCommandeUtilisateursRestants,
            },
          },
        },
      },
    },
  });
};

const supprimeCommandeContenusFournisseur = (state, fournisseurId, commandeId) => {
  const {
    commandeContenus,
    offres,
    produits,
    commandeUtilisateurs,
  } = state.datas.entities;

  const commandeContenusASupprimerIds = Object.keys(commandeContenus).filter(
    id =>
      commandeContenus[id].commandeId === commandeId &&
      produits[offres[commandeContenus[id].offreId].produitId].fournisseurId === fournisseurId
  );

  const commandeUtilisateursModifiee = uniq(
    // il peut y a voir plusieurs contenus pour une meme commandeUtilisateur
    commandeContenusASupprimerIds.map(ccId => commandeContenus[ccId].commandeUtilisateurId)
  ).reduce(
    (memo, cuId) => ({
      ...memo,
      [cuId]: {
        ...commandeUtilisateurs[cuId],
        contenus: commandeUtilisateurs[cuId].contenus.filter(
          id => !includes(commandeContenusASupprimerIds, id)
        ),
      },
    }),
    {}
  );

  const commandeContenusModifiee = Object.keys(commandeContenus)
    .filter(id => !includes(commandeContenusASupprimerIds, id))
    .reduce(
      (memo, id) => ({
        ...memo,
        [id]: commandeContenus[id],
      }),
      {}
    );

  return update(state, {
    datas: {
      entities: {
        commandeContenus: {
          $set: { ...commandeContenus, ...commandeContenusModifiee },
        },
        commandeUtilisateurs: {
          $set: { ...commandeUtilisateurs, ...commandeUtilisateursModifiee },
        },
      },
    },
  });
};

const supprimeContenu = (state, contenu) => {
  const { commandeUtilisateurs, commandeContenus } = state.datas.entities;
  const contenusRestants = commandeUtilisateurs[contenu.commandeUtilisateurId].contenus.filter(
    cont => cont !== contenu.id
  ); // eslint-disable-line
  const commandeContenusRestants = Object.keys(commandeContenus).reduce(
    (memo, cont) => {
      const aIns = cont.id !== contenu.id ? { [contenu.id]: contenu } : {};
      return { ...memo, aIns };
    },
    {}
  );
  return update(state, {
    datas: {
      entities: {
        commandeUtilisateurs: {
          [contenu.commandeUtilisateurId]: {
            contenus: { $set: contenusRestants },
          },
          commandeContenus: { $set: commandeContenusRestants },
        },
      },
    },
  });
};

// const majNouvelAchat = (state, commandeContenu) => {
//   const majCu = update(
//     state,
//     { datas:
//       { entities:
//         { commandeUtilisateurs:
//           { [commandeContenu.commandeUtilisateurId]:
//             { contenus: { $push: [commandeContenu] },
//           },
//         },
//       },
//     },
//     },
//   );
//   // const produit = state.datas.entities.produits[state.datas.entities.offres[commandeContenu.offreId].produitId];
//   // const nStock = produit.stock - commandeContenu.quantite;
//   // return update(majCu, { datas: { entities: { produits: { [produit.id]: { stock: { $set: nStock } } } } } });
//   return majCu;
// };

function commandeReducer(state = initialState, action) {
  switch (action.type) {
    case c.ASYNC_LOAD_FOURNISSEURS_SUCCESS: {
      const datas = normalize(action.datas.fournisseurs, arrayOf(schemas.FOURNISSEURS));
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
          result: { $push: datas.result },
        },
        pending: { $set: false },
      });
    }
    case c.ASYNC_LOAD_OFFRES_SUCCESS: {
      const datas = normalize(action.datas.offre_produits, arrayOf(schemas.OFFRES));
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
          result: { $push: datas.result },
        },
        pending: { $set: false },
      });
    }
    case c.ASYNC_LOAD_USER_COMMANDES_SUCCESS:
    case c.ASYNC_LOAD_COMMANDES_SUCCESS: {
      const datas = normalize(action.datas.commandes, arrayOf(schemas.COMMANDES));
      const defaults = {
        commandes: {},
        commandeContenus: {},
        commandeUtilisateurs: {},
        livraisons: {},
        fournisseurs: {},
      };
      return update(state, {
        datas: {
          entities: {
            $set: merge(state.datas.entities, assign(defaults, datas.entities)),
          },
          result: { $push: datas.result },
        },
        pending: { $set: false },
      });
    }
    // case cE.ASYNC_SAUVEGARDER_SUCCESS: {
    //   const datas = normalize(action.datas, schemas.COMMANDE_UTILISATEURS);
    //   return update(state, {
    //     datas: {
    //       entities: { $set: merge(state.datas.entities, datas.entities) },
    //       result: { $push: [datas.result] },
    //     },
    //     pending: { $set: false },
    //   });
    // }

    case cE.ASYNC_ANNULER_SUCCESS: {
      const { commandeId, id } = action.req.datas;
      return annuleCommandeUtilisateur(state, id, commandeId);
    }

    case c.ASYNC_CREATE_COMMANDE_SUCCESS:
    case c.ASYNC_LOAD_COMMANDE_SUCCESS: {
      const datas = normalize(action.datas, schemas.COMMANDES);
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
          result: { $push: [datas.result] },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_DELETE_COMMANDE_SUCCESS: {
      const { id } = action.req.datas;
      const { commandes } = state.datas.entities;
      const commandesRestantes = Object.keys(commandes).reduce(
        (memo, key) => key !== id ? { ...memo, [key]: commandes[key] } : memo,
        {}
      );

      return update(state, {
        datas: { entities: { commandes: { $set: commandesRestantes } } },
      });
    }

    case c.ASYNC_LOAD_RELAIS_SUCCESS: {
      const datas = normalize(action.datas.relais, arrayOf(schemas.RELAIS));
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_SAVE_PRODUIT_SUCCESS: {
      const datas = normalize(action.datas, schemas.PRODUITS);

      return update(state, {
        datas: {
          entities: {
            produits: {
              [action.datas.id]: {
                $set: datas.entities.produits[action.datas.id],
              },
            },
            pending: { $set: false },
          },
        },
      });
    }

    case c.ASYNC_SAVE_OFFRE_SUCCESS: {
      const datas = normalize(action.datas, schemas.OFFRES);

      return update(state, {
        datas: {
          entities: {
            offres: {
              [action.datas.id]: {
                $set: datas.entities.offres[action.datas.id],
              },
            },
            pending: { $set: false },
          },
        },
      });
    }

    case c.ASYNC_IMPORTE_OFFRES_SUCCESS: {
      const datas = normalize(action.datas.offres, schemas.OFFRES);
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_LOAD_TYPES_PRODUITS_SUCCESS: {
      const datas = normalize(action.datas.type_produits, arrayOf(schemas.TYPES_PRODUITS));
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_LOAD_FOURNISSEUR_SUCCESS:
    case cF.ASYNC_LOAD_FOURNISSEUR_SUCCESS: {
      const datas = normalize(action.datas, schemas.FOURNISSEURS);
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_MODIFIER_COMMANDE_CONTENU_SUCCESS: {
      const datas = normalize(action.datas, schemas.COMMANDE_CONTENUS);
      return update(state, {
        datas: {
          entities: {
            commandeContenus: {
              [action.datas.id]: {
                $set: datas.entities.commandeContenus[action.datas.id],
              },
            },
          },
        },
      });
    }

    case c.ASYNC_SUPPRIMER_COMMANDE_CONTENUS_FOURNISSEUR_SUCCESS: {
      const { fournisseurId, commandeId } = action.req.datas;
      return supprimeCommandeContenusFournisseur(state, fournisseurId, commandeId);
    }

    case c.ASYNC_PAYE_COMMANDE_UTILISATEUR_SUCCESS:
    case c.ASYNC_LIVRE_COMMANDE_UTILISATEUR_SUCCESS: {
      const datas = normalize(action.datas, schemas.COMMANDE_UTILISATEURS);
      return update(state, {
        datas: {
          entities: {
            commandeUtilisateurs: {
              [action.datas.id]: {
                $set: datas.entities.commandeUtilisateurs[action.datas.id],
              },
            },
          },
        },
      });
    }

    case c.AJOUTER:
      return ajouter(state, action);
    case c.NOUVEL_ACHAT: {
      const nCommandeContenus = {
        ...state.datas.entities.commandeContenus,
        [action.datas.id]: action.datas,
      };
      return update(state, {
        datas: { entities: { commandeContenus: { $set: nCommandeContenus } } },
      });
    }
    case c.SUPPRESSION_ACHAT: {
      const nCommandeContenus = omit(state.datas.entities.commandeContenus, action.datas.id);
      return update(state, {
        datas: { entities: { commandeContenus: { $set: nCommandeContenus } } },
      });
    }
    case c.MODIF_ACHAT: {
      return update(state, {
        datas: {
          entities: {
            commandeContenus: {
              $set: {
                ...state.datas.entities.commandeContenus,
                [action.datas.id]: action.datas,
              },
            },
          },
        },
      });
    }

    case c.ASYNC_SUPPRIMER_COMMANDE_CONTENU_SUCCESS:
      return supprimeContenu(state, action.req.datas);

    case c.ASYNC_LOAD_UTILISATEURS_SUCCESS: {
      const datas = normalize(action.datas.utilisateurs, arrayOf(schemas.UTILISATEURS));
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_LOAD_COMMANDE_UTILISATEURS_SUCCESS: {
      const datas = normalize(action.datas.commande_utilisateurs, arrayOf(schemas.COMMANDE_UTILISATEURS));
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
        },
        pending: { $set: false },
      });
    }

    case c.ASYNC_SAVE_UTILISATEUR_SUCCESS: {
      const datas = normalize(action.datas, schemas.UTILISATEURS);

      return update(state, {
        datas: {
          entities: {
            utilisateurs: {
              [action.datas.id]: {
                $set: datas.entities.utilisateurs[action.datas.id],
              },
            },
            pending: { $set: false },
          },
        },
      });
    }

    case 'ws/NOUVELLE_COMMANDE_UTILISATEUR': {
      const datas = normalize(action.datas, schemas.COMMANDE_UTILISATEURS);
      return update(state, {
        datas: {
          entities: { $set: merge(state.datas.entities, datas.entities) },
        },
        pending: { $set: false },
      });
    }

    // case 'ws/NOUVEL_ACHAT': // websocket
    //   return majNouvelAchat(state, action.datas);
    case 'ws/OFFRE_MODIF_STOCK':
      return update(state, {
        datas: {
          entities: {
            offres: {
              [action.datas.id]: { stock: { $set: action.datas.stock } },
            },
          },
        },
      });
    default:
      return state;
  }
}

export default commandeReducer;
<|endoftext|>


<commit_before>exports.config = {
  allScriptsTimeout: 11000,

  specs: [
    '*.js'
  ],

  capabilities: {
    'browserName': 'chrome'
  },

  baseUrl: 'http://localhost:8000/app/',

  framework: 'jasmine',

  jasmineNodeOpts: {
    defaultTimeoutInterval: 30000
  }
};
<commit_msg>Fixed baseUrl for new routes.<commit_after>exports.config = {
  allScriptsTimeout: 11000,

  specs: [
    '*.js'
  ],

  capabilities: {
    'browserName': 'chrome'
  },

  baseUrl: 'http://localhost:8000/',

  framework: 'jasmine',

  jasmineNodeOpts: {
    defaultTimeoutInterval: 30000
  }
};
<|endoftext|>