import getSelectable from './getSelectable.util' ; import getColor from './colors.util' ; import cloneDeep from './cloneDeep' ; import { ComponentInt , ApplicationStateInt , ChildrenInt , ChildInt , ComponentsInt , PropInt , ReducersInterface , InterfacesInterface , ComponentStateInterface , } from './InterfaceDefinitions' ; const initialComponentState = { id : 0 , stateful : false , componentState : [ ] , title : '' , color : getColor ( 1 ) , props : [ ] , nextPropId : 1 , childrenArray : [ ] , nextChildId : 1 , focusChildId : 0 , selectors : [ ] , actions : [ ] , } ; export const addComponent = ( state , { title } ) => { const strippedTitle = title . replace ( /[a-z]+/gi , word => word [ 0 ] . toUpperCase ( ) + word . slice ( 1 ) ) . replace ( /[^a-zA-Z]+/gi , '' ) ; if ( state . components . find ( ( comp ) => comp . title === strippedTitle ) ) { window . alert ( `A component with the name: "${ strippedTitle }" already exists.\n Please think of another name.` ) ; return { ... state , } ; } if ( strippedTitle === '' ) { return { ... state , } ; } const componentColor = getColor ( 1 ) ; const componentId = state . nextId ; const newComponent = { ... initialComponentState , title : strippedTitle , id : componentId , color : componentColor , childrenArray : [ ] , } ; const components = [ ... state . components , newComponent ] ; const totalComponents = state . totalComponents + 1 ; const nextId = state . nextId + 1 ; const selectableChildren = state . components . map ( comp => comp . id ) . filter ( id => id !== newComponent . id ) ; const ancestors = [ ] ; const newFocusChild = cloneDeep ( state . initialApplicationFocusChild ) ; return { ... state , totalComponents , nextId , components , focusComponent : newComponent , focusChild : newFocusChild , ancestors , selectableChildren , } ; } ; export const addChild = ( state , { title , childType = '' , HTMLInfo = { } } ) => { const strippedTitle = title ; if ( ! childType ) { window . alert ( 'addChild Error! no type specified' ) ; } const htmlElement = childType !== 'COMP' ? childType : null ; if ( childType !== 'COMP' ) { childType = 'HTML' ; } const view = state . components . find ( comp => comp . title === state . focusComponent . title ) ; let parentComponent ; if ( childType === 'COMP' ) { parentComponent = state . components . find ( comp => comp . title === title ) ; } const newChild = { childId : view . nextChildId , childSort : view . nextChildId , childType , childComponentId : childType === 'COMP' ? parentComponent . id : null , componentName : strippedTitle , color : null , htmlElement , HTMLInfo , } ; const compsChildrenArr = [ ... view . childrenArray , newChild ] ; const component = { ... view , childrenArray : compsChildrenArr , focusChildId : newChild . childId , nextChildId : view . nextChildId + 1 , } ; const components = [ ... state . components . filter ( ( comp ) => { if ( comp . title !== view . title ) return comp ; } ) , component , ] ; return { ... state , components , focusChild : newChild , focusComponent : component , } ; } ; export const deleteChild = ( state , opts ) => { let childId ; let parentId ; let calledFromDeleteComponent ; if ( typeof opts === 'number' ) { childId = opts ; parentId = state . focusComponent . id ; calledFromDeleteComponent = false ; } else { parentId = opts . parentId ; childId = opts . childId ; calledFromDeleteComponent = opts . calledFromDeleteComponent ; } /** ************************************************
    if no parameters are provided we default to delete the FOCUSED CHILD of the FOCUSED COMPONENTS
    however when deleting  component we wnt to delete ALL the places where it's used, so we call this function
    Also when calling from DELETE components , we do not touch focusComponent.
   ************************************************************************************ */ if ( ! parentId ) { window . alert ( 'Cannot delete root child of a component' ) ; return state ; } if ( ! childId ) { window . alert ( 'No child selected' ) ; return state ; } if ( ! calledFromDeleteComponent && childId === - 1 ) { window . alert ( 'Cannot delete root child of a component' ) ; return state ; } const parentComponentCopy = cloneDeep ( state . components . find ( c => c . id === parentId ) ) ; const indexToDelete = parentComponentCopy . childrenArray . findIndex ( ( elem ) => elem . childId === childId || elem . childComponentId === childId ) ; if ( indexToDelete < 0 ) { window . alert ( 'No such child component found' ) ; return state ; } parentComponentCopy . childrenArray . splice ( indexToDelete , 1 ) ; if ( parentComponentCopy . focusChildId === childId ) { parentComponentCopy . focusChildId = 0 ; } const modifiedComponentArray = [ ... state . components . filter ( c => c . id !== parentId ) , parentComponentCopy , ] ; return { ... state , components : modifiedComponentArray , focusComponent : parentComponentCopy , focusChild : calledFromDeleteComponent ? cloneDeep ( state . initialApplicationFocusChild ) : parentComponentCopy . childrenArray [ parentComponentCopy . childrenArray . length - 1 ] || cloneDeep ( state . initialApplicationFocusChild ) , } ; } ; export const handleTransform = ( state , { componentId , childId , } ) => { if ( childId === - 1 ) { const component = state . components . find ( comp => comp . id === componentId ) ; const transformedComponent = { ... component , } ; const components = [ ... state . components . filter ( ( comp ) => { if ( comp . id !== componentId ) return comp ; } ) , transformedComponent , ] ; return { ... state , components } ; } const child = state . components . find ( comp => comp . id === componentId ) . childrenArray . find ( child => child . childId === childId ) ; const transformedChild = { ... child , } ; const children = [ ... state . components . find ( comp => comp . id === componentId ) . childrenArray . filter ( ( child ) => { if ( child . childId !== childId ) return child ; } ) , transformedChild , ] ; let newFocusChild = state . focusChild ; if ( state . focusChild . childId == childId ) { newFocusChild = transformedChild ; } const component = { ... state . components . find ( comp => comp . id === componentId ) , childrenArray : children , focusChild : newFocusChild , } ; const components = [ ... state . components . filter ( ( comp ) => { if ( comp . id !== componentId ) return comp ; } ) , component , ] ; return { ... state , components , focusChild : newFocusChild , } ; } ; export const deleteComponent = ( state , { componentId } ) => { if ( componentId === 1 ) { return { ... state , } ; } const indexToDelete = state . components . findIndex ( comp => comp . id == componentId ) ; const componentsCopy = cloneDeep ( state . components ) ; componentsCopy . splice ( indexToDelete , 1 ) ; const totalComponents = state . totalComponents - 1 ; return { ... state , totalComponents , components : componentsCopy , } ; } ; export const changeFocusComponent = ( state , { title = state . focusComponent . title } ) => { /** ****************
     * if the prm TITLE is a blank Object it means REFRESH focusd Components.
     * sometimes we update state  like adding Children/Props etc and we want those changes to be reflected in focus component
     ************************************************* */ const newFocusComp = state . components . find ( comp => comp . title === title ) ; let newFocusChild ; if ( newFocusComp . focusChildId > 0 ) { newFocusChild = newFocusComp . childrenArray . find ( child => child . childId === newFocusComp . focusChildId ) ; } if ( ! newFocusChild ) { newFocusChild = cloneDeep ( state . initialApplicationFocusChild ) ; } const result = getSelectable ( newFocusComp , state . components ) ; return { ... state , focusComponent : newFocusComp , selectableChildren : result . selectableChildren , ancestors : result . ancestors , focusChild : newFocusChild , } ; } ; export const changeFocusChild = ( state , { childId } ) => { const focComp = state . components . find ( comp => comp . title === state . focusComponent . title ) ; let newFocusChild = focComp . childrenArray . find ( child => child . childId === childId ) ; if ( ! newFocusChild ) { newFocusChild = { childId : - 1 , childComponentId : focComp . id , componentName : focComp . title , childSort : 0 , color : focComp . color , childType : '' , htmlElement : '' , HTMLInfo : { } , } ; } return { ... state , focusChild : newFocusChild , } ; } ; export const changeComponentFocusChild = ( state , { componentId , childId } ) => { const component = state . components . find ( comp => comp . id === componentId ) ; const modifiedComponent = cloneDeep ( component ) ; modifiedComponent . focusChildId = childId ; const components = state . components . filter ( comp => comp . id !== componentId ) ; return { ... state , components : [ modifiedComponent , ... components ] , } ; } ; export const exportFilesSuccess = ( state , { status , dir } ) => ( { ... state , successOpen : status , appDir : dir , loading : false , } ) ; export const exportFilesError = ( state , { status , err } ) => { console . log ( 'error exporting files' , err ) ; return { ... state , errorOpen : status , loading : false , } ; } ; export const handleClose = ( state , status ) => ( { ... state , errorOpen : status , successOpen : status , } ) ; export const openExpansionPanel = ( state , { component } ) => ( { ... state , } ) ; export const addProp = ( state , { key , value = null , required , type , } ) => { if ( ! state . focusComponent . id ) { console . log ( 'Add prop error. no focused component ' ) ; return state ; } const selectedComponent = state . components . find ( comp => comp . id === state . focusComponent . id ) ; const newProp = { id : selectedComponent . nextPropId , key , value : value || key , required , type , } ; const newProps = [ ... selectedComponent . props , newProp ] ; const modifiedComponent = { ... selectedComponent , props : newProps , nextPropId : selectedComponent . nextPropId + 1 , } ; const newComponents = state . components . filter ( comp => comp . id !== selectedComponent . id ) ; newComponents . push ( modifiedComponent ) ; return { ... state , components : newComponents , focusComponent : modifiedComponent , } ; } ; export const deleteProp = ( state , propId ) => { if ( ! state . focusComponent . id ) { console . log ( 'Delete prop error. no focused component ' ) ; return state ; } const modifiedComponent = cloneDeep ( state . components . find ( comp => comp . id === state . focusComponent . id ) ) ; const indexToDelete = modifiedComponent . props . findIndex ( ( prop ) => prop . id === propId ) ; if ( indexToDelete === - 1 ) { console . log ( `Delete prop Error. Prop id:${ propId } not found in ${ modifiedComponent . title }` ) ; return state ; } modifiedComponent . props . splice ( indexToDelete , 1 ) ; const newComponentsArray = state . components . filter ( comp => comp . id !== modifiedComponent . id ) ; newComponentsArray . push ( modifiedComponent ) ; return { ... state , components : newComponentsArray , focusComponent : modifiedComponent , } ; } ; export const updateHtmlAttr = ( state , { attr , value } ) => { if ( ! state . focusChild . childId ) { console . log ( 'Update HTML error. no focused child ' ) ; return state ; } const modifiedChild = cloneDeep ( state . focusChild ) ; modifiedChild . HTMLInfo [ attr ] = value ; const modifiedComponent = JSON . parse ( JSON . stringify ( state . components . find ( comp => comp . id === state . focusComponent . id ) ) ) ; modifiedComponent . childrenArray = modifiedComponent . childrenArray . filter ( child => child . childId !== modifiedChild . childId ) ; modifiedComponent . childrenArray . push ( modifiedChild ) ; const newComponentsArray = state . components . filter ( comp => comp . id !== modifiedComponent . id ) ; newComponentsArray . push ( modifiedComponent ) ; return { ... state , components : newComponentsArray , focusComponent : modifiedComponent , focusChild : modifiedChild , } ; } ; export const updateChildrenSort = ( state , { newSortValues } ) => { const modifiedChildrenArray = cloneDeep ( state . focusComponent . childrenArray ) ; for ( let i = 0 ; i < modifiedChildrenArray . length ; i += 1 ) { const currChild = modifiedChildrenArray [ i ] ; const currChildId = currChild . childId ; const newValueObj = newSortValues . find ( ( n ) => n . childId === currChildId ) ; const newSortValue = newValueObj . childSort ; currChild . childSort = newSortValue ; } const modifiedComponent = state . components . find ( comp => comp . id === state . focusComponent . id ) ; modifiedComponent . childrenArray = modifiedChildrenArray ; const modifiedComponentsArray = state . components . filter ( comp => comp . id !== state . focusComponent . id ) ; modifiedComponentsArray . push ( modifiedComponent ) ; return { ... state , components : modifiedComponentsArray , focusComponent : modifiedComponent , } ; } ; export const addSelector = ( state , payload ) => { const components = [ ... state . components ] ; const index = components . findIndex ( comp => comp . title === state . focusComponent . title ) ; const view = { ... components [ index ] } ; view . selectors = view . selectors . includes ( payload ) ? [ ... view . selectors ] : [ ... view . selectors , payload ] ; components . splice ( index , 1 , view ) ; const focusComponent = { ... state . focusComponent } ; focusComponent . selectors = focusComponent . selectors . includes ( payload ) ? [ ... focusComponent . selectors ] : [ ... focusComponent . selectors , payload ] ; return { ... state , components , focusComponent , } ; } ; export const deleteSelector = ( state , payload ) => { const components = [ ... state . components ] ; const index = components . findIndex ( comp => comp . title === state . focusComponent . title ) ; const view = { ... components [ index ] } ; view . selectors = view . selectors . filter ( selector => selector !== payload ) ; components . splice ( index , 1 , view ) ; const focusComponent = { ... state . focusComponent } ; focusComponent . selectors = view . selectors . filter ( selector => selector !== payload ) ; return { ... state , components , focusComponent , } ; } ; export const addActionToComponent = ( state , payload ) => { const components = [ ... state . components ] ; const index = components . findIndex ( comp => comp . title === state . focusComponent . title ) ; const view = { ... components [ index ] } ; view . actions = view . actions . includes ( payload ) ? [ ... view . actions ] : [ ... view . actions , payload ] ; components . splice ( index , 1 , view ) ; const focusComponent = { ... state . focusComponent } ; focusComponent . actions = focusComponent . actions . includes ( payload ) ? [ ... focusComponent . actions ] : [ ... focusComponent . actions , payload ] ; return { ... state , components , focusComponent , } ; } ; export const deleteActionFromComponent = ( state , payload ) => { const components = [ ... state . components ] ; const index = components . findIndex ( comp => comp . title === state . focusComponent . title ) ; const view = { ... components [ index ] } ; view . actions = view . actions . filter ( action => action !== payload ) ; components . splice ( index , 1 , view ) ; const focusComponent = { ... state . focusComponent } ; focusComponent . actions = view . actions . filter ( action => action !== payload ) ; return { ... state , components , focusComponent , } ; } ; export const setReducer = ( state , payload ) => { const reducerName = Object . keys ( payload ) [ 0 ] ; const reducerStore = payload [ reducerName ] . store ; const reducerActions = payload [ reducerName ] . actions ; const components = state . components . map ( ( component ) => { const selectors = component . selectors . filter ( ( selector ) => { const [ curReducerName , curSelectorName ] = selector . split ( '.' ) ; return state . storeConfig . reducers [ curReducerName ] && reducerStore [ curSelectorName ] ; } ) ; const actions = component . actions . filter ( ( action ) => { const [ curReducerName , curActionName ] = action . split ( '.' ) ; return state . storeConfig . reducers [ curReducerName ] && reducerActions [ curActionName ] ; } ) ; return { ... component , selectors , actions } ; } ) ; let focusComponent = { ... state . focusComponent } ; const selectors = focusComponent . selectors . filter ( ( selector ) => { const [ curReducerName , curSelectorName ] = selector . split ( '.' ) ; return state . storeConfig . reducers [ curReducerName ] && reducerStore [ curSelectorName ] ; } ) ; const actions = focusComponent . actions . filter ( ( action ) => { const [ curReducerName , curActionName ] = action . split ( '.' ) ; return state . storeConfig . reducers [ curReducerName ] && reducerActions [ curActionName ] ; } ) ; focusComponent = { ... focusComponent , selectors , actions } ; const storeConfig = { interfaces : { ... state . storeConfig . interfaces , } , reducers : { ... state . storeConfig . reducers , ... payload , } } ; return { ... state , storeConfig , components , focusComponent } ; } ; export const deleteReducer = ( state , payload ) => { const components = state . components . map ( ( component ) => { const selectors = component . selectors . filter ( ( selector ) => { const [ curReducerName , curSelectorName ] = selector . split ( '.' ) ; return curReducerName !== payload ; } ) ; const actions = component . actions . filter ( ( action ) => { const [ curReducerName , curActionName ] = action . split ( '.' ) ; return curReducerName !== payload ; } ) ; return { ... component , selectors , actions } ; } ) ; let focusComponent = { ... state . focusComponent } ; const selectors = focusComponent . selectors . filter ( ( selector ) => { const [ curReducerName , ] = selector . split ( '.' ) ; return curReducerName !== payload ; } ) ; const actions = focusComponent . actions . filter ( ( action ) => { const [ curReducerName , ] = action . split ( '.' ) ; return curReducerName !== payload ; } ) ; focusComponent = { ... focusComponent , selectors , actions } ; const storeConfig = { interfaces : { ... state . storeConfig . interfaces , } , reducers : { ... state . storeConfig . reducers , } , } ; delete storeConfig . reducers [ payload ] ; return { ... state , storeConfig , components , focusComponent } ; } ; export const setInterface = ( state , payload ) => { const storeConfig = { interfaces : { ... state . storeConfig . interfaces , ... payload , } , reducers : { ... state . storeConfig . reducers , } , } ; return { ... state , storeConfig , } ; } ; export const deleteInterface = ( state , payload ) => { const storeConfig = { interfaces : { ... state . storeConfig . interfaces , } , reducers : { ... state . storeConfig . reducers , } , } ; delete storeConfig . interfaces [ payload ] ; let components = [ ... state . components ] ; components = components . map ( ( component ) => { let componentState = [ ... component . componentState ] ; componentState = componentState . filter ( ( localStatePiece ) => localStatePiece . type !== payload ) ; return { ... component , componentState } ; } ) ; const focusComponent = { ... state . focusComponent } ; const newFocusComponentState = [ ... focusComponent . componentState ] ; focusComponent . componentState = newFocusComponentState . filter ( ( localStatePiece ) => localStatePiece . type !== payload ) ; return { ... state , storeConfig , components , focusComponent } ; } ; export const setState = ( state , payload ) => { const components = [ ... state . components ] ; const index = components . findIndex ( comp => comp . title === state . focusComponent . title ) ; const view = { ... components [ index ] } ; const stateIndex = view . componentState . findIndex ( state => state . name === payload . name ) ; if ( stateIndex !== - 1 ) { view . componentState . splice ( stateIndex , 1 , payload ) ; } else { view . componentState = [ ... view . componentState , payload ] ; } components . splice ( index , 1 , view ) ; const focusComponent = { ... state . focusComponent } ; const stateIndexFocus = focusComponent . componentState . findIndex ( state => state . name === payload . name ) ; if ( stateIndexFocus !== - 1 ) { focusComponent . componentState . splice ( stateIndexFocus , 1 , payload ) ; } else { focusComponent . componentState = [ ... focusComponent . componentState , payload ] ; } return { ... state , components , focusComponent , } ; } ; export const deleteState = ( state , payload ) => { const components = [ ... state . components ] ; const index = components . findIndex ( comp => comp . title === state . focusComponent . title ) ; const view = { ... components [ index ] } ; view . componentState = view . componentState . filter ( pieceOfState => pieceOfState . name !== payload ) ; components . splice ( index , 1 , view ) ; const focusComponent = { ... state . focusComponent } ; focusComponent . componentState = focusComponent . componentState . filter ( pieceOfState => pieceOfState . name !== payload ) ; return { ... state , components , focusComponent , } ; } ;