Skip to content

Commit

Permalink
refactor(global): ♻️ made reducer for store builder data
Browse files Browse the repository at this point in the history
the one builder instance is created is once

Ref #54
  • Loading branch information
PritamBag committed Jan 6, 2025
1 parent 0903a6c commit 00a7624
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 138 deletions.
69 changes: 69 additions & 0 deletions app/actions/builder.actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { AppBuilderData } from "../components/data/app-builder/AppBuilder.data";
import { DynamicEntity } from "../components/data/app-builder/DynamicEntity.interface";
import { BuilderState } from "../reducers/builder.reducer";
import { SET_BUILDER_DATA } from "../types/builder.types";

// export const setBuilderData_Case1 = (data: {[key: string]: string}) => (dispatch) => {
// dispatch({
// payload: data,
// type : BUILDER_DATA_CASE_1
// });
// };

// export const setBuilderData = (builderData: AppBuilderData, entityData: DynamicEntity) => {
// return {
// payload: { builderData, entityData },
// type : SET_BUILDER_DATA
// };
// };

// export const setBuilderData = (builderData: AppBuilderData, entityData: DynamicEntity, currentState: BuilderState) => {
// const existingBuilderIndex = currentState.appBuilderData.findIndex(
// (data) => data.builderId === builderData.builderId
// );

// let updatedAppBuilderData;

// if (existingBuilderIndex > -1) {
// // Update existing builderData's entityData
// updatedAppBuilderData = currentState.appBuilderData.map((data, index) =>
// index === existingBuilderIndex ? { ...data, entityData } : data
// );
// } else {
// // Add new builderData to the state
// updatedAppBuilderData = [...currentState.appBuilderData, { ...builderData, entityData }];
// }

// return {
// payload: { appBuilderData: updatedAppBuilderData },
// type : SET_BUILDER_DATA
// };
// };

export const setBuilderData = (builderData: AppBuilderData, entityData: DynamicEntity, currentState: BuilderState) => {
const existingBuilderIndex = currentState.appBuilderData.findIndex(
(data) => data.builderId === builderData.builderId
);

let updatedAppBuilderData;

if (existingBuilderIndex > -1) {
// Update existing builderData's entityData using the setter method
updatedAppBuilderData = currentState.appBuilderData.map((data, index) => {
if (index === existingBuilderIndex) {
// Directly update the entityData using the setter
data.setEntityData(entityData); // Use setter to update entityData
}
return data;
});
} else {
// Add new builderData to the state and set entityData
builderData.setEntityData(entityData);
updatedAppBuilderData = [...currentState.appBuilderData, builderData];
}

return {
payload: { appBuilderData: updatedAppBuilderData },
type : SET_BUILDER_DATA
};
};
62 changes: 43 additions & 19 deletions app/components/AppBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import React, { useEffect, useState } from "react";

import {
CoreLayoutItem, CoreIconButton, CoreTooltip, CoreIcon, CoreGrid, CoreBox, AppBuilderContainerLayout, CoreTypographyBody1, CoreTypographyOverline, CoreClasses, coreUseLocation
CoreLayoutItem, CoreTypographyBody1, CoreTypographyOverline, CoreIconButton, CoreTooltip, CoreIcon, CoreGrid, CoreBox, AppBuilderContainerLayout, CoreClasses, coreUseLocation
} from "@wrappid/core";
import { useDispatch, useSelector } from "react-redux";

Expand All @@ -11,8 +11,8 @@ import { DynamicEntity } from "./data/app-builder/DynamicEntity.interface";
import ToolbarGroup from "./toolbar/ToolbarGroup";
import ToolBoxGroup from "./toolbox/ToolBoxGroup";
import { GetDataFromReducer, getBuilderData, getBuilderType } from "./UtilityFunction";
import ViewerGroup from "./viewers/ViewerGroup";
import { addAppBuilderDataToReducer } from "../actions/reducer.action";
import ViewerGroup from "./viewer/ViewerGroup";
import { setBuilderData } from "../actions/builder.actions";
import { CLOSE, CLOSE_FUNCTIONALITY_COMMING_SOON, PRIMARY, SMALL } from "../constants/AppBuilder.constant";
import AppBuilderFactory from "../factory/AppBuilder.factory";
import ModuleClasses from "../styles/ModuleClasses";
Expand All @@ -32,35 +32,59 @@ export function getBuilderState(): BuilderState {
export default function AppBuilder<T extends AppBuilderData>() {
const dispatch = useDispatch();
const builderType = getBuilderType();
const data = getBuilderData();

const appBuilderData:T = AppBuilderFactory.getAppBuilderData(builderType);

useEffect(() => {
dispatch(addAppBuilderDataToReducer(appBuilderData, data));
}, [data]);
const entityData = getBuilderData();

const [selectedBuilderId, setSelectedBuilderId] = useState<string>(GetDataFromReducer(data?.id)?.builderId);
const appBuilderDataFromReducer = useSelector((state: any) => state.BuilderOptions?.appBuilderData);
const selectedBuilder = appBuilderDataFromReducer?.find(
(builder: any) => builder.builderId === selectedBuilderId
const [selectedBuilderId, setSelectedBuilderId] = useState<string>(GetDataFromReducer(entityData?.id)?.builderId);
const appBuilderDataFromStore = useSelector((state: any) => state.BuilderOptions?.appBuilderData);
const selectedBuilder = appBuilderDataFromStore?.find(
(builderData: AppBuilderData) => builderData.builderId === selectedBuilderId
);

const currentState = useSelector((state: any) => state.BuilderOptions);

const viewerData = selectedBuilder?.viewers;
const toolboxData = selectedBuilder?.toolboxes;
const toolbarData = selectedBuilder?.toolbars;

const checkIfBuilderExist = () => {
// check builderData.id
const builderData = appBuilderDataFromStore?.find(
(_builderData: AppBuilderData) => {
Object.setPrototypeOf(_builderData, AppBuilderData.prototype);
return _builderData.getBuilderType() === builderType && _builderData.getEntityData().id === entityData?.id;
});

if(builderData) {
return true;
}

return false;
};

useEffect(() => {
if(!checkIfBuilderExist()){
const appBuilderData:T = AppBuilderFactory.getAppBuilderData(builderType);

dispatch(setBuilderData(appBuilderData, entityData, currentState));
}
}, [entityData]);

useEffect(() => {
/* Change in the store */
// dispatch(setBuilderData_Case1(data));
}, [/* dependency */]);

return (
<>
{/* Header area of pagebuilder */}
<CoreLayoutItem id={AppBuilderContainerLayout.PLACEHOLDER.Header} styleClasses={[CoreClasses.BG.BG_GREY_200]}>
<CoreGrid>
<CoreBox gridProps={{ gridSize: 9 }} styleClasses={[ModuleClasses.BUILDER_TAB_GROUP]}>
{appBuilderDataFromReducer && appBuilderDataFromReducer.length > 0 ? (
appBuilderDataFromReducer.map((eachBuilderData, index) => {
{appBuilderDataFromStore && appBuilderDataFromStore.length > 0 ? (
appBuilderDataFromStore.map((eachBuilderData, index) => {
Object.setPrototypeOf(eachBuilderData, AppBuilderData.prototype);

const isLastItem = index === appBuilderDataFromReducer.length - 1;
const isLastItem = index === appBuilderDataFromStore.length - 1;

return (
<CoreBox
Expand All @@ -75,10 +99,10 @@ export default function AppBuilder<T extends AppBuilderData>() {
]}
onClick={() => setSelectedBuilderId(eachBuilderData.builderId)}
>
<CoreTooltip title={eachBuilderData?.getBuilderData()[0]?.name} arrow>
<CoreTooltip title={eachBuilderData?.getEntityData()?.name} arrow>
<CoreBox styleClasses={[ModuleClasses.BUILDER_TAB_BOX]}>
<CoreIcon icon={eachBuilderData?.getBuilderIcon()} color={PRIMARY} fontSize={SMALL}/>
<CoreTypographyOverline paragraph={false} gutterBottom={false} styleClasses={[ModuleClasses.BUILDER_TAB_NAME]}>{eachBuilderData?.getBuilderData()[0]?.name}</CoreTypographyOverline>
<CoreTypographyOverline paragraph={false} gutterBottom={false} styleClasses={[ModuleClasses.BUILDER_TAB_NAME]}>{eachBuilderData?.getEntityData()?.name}</CoreTypographyOverline>
</CoreBox>
</CoreTooltip>
<CoreTooltip title={CLOSE_FUNCTIONALITY_COMMING_SOON} arrow>
Expand Down
125 changes: 7 additions & 118 deletions app/reducers/builder.reducer.ts
Original file line number Diff line number Diff line change
@@ -1,131 +1,20 @@
import { AppBuilderData } from "../components/data/app-builder/AppBuilder.data";
import { FormattedAttribute } from "../components/data/viewer/FormattedAttribute";
import { ADD_APP_BUILDER_DATA_TO_REDUCER, ADD_ATTRIBUTE, UPDATE_ATTRIBUTE_SELECTED_PROPS } from "../types/builder.types";
import { recreateBuilderInstance, updateViewerContent, updateViewers } from "../utils/builderUtils";
import { SET_BUILDER_DATA } from "../types/builder.types";

export interface BuilderState {
appBuilderData: AppBuilderData[];
}

const initialState: BuilderState = { appBuilderData: [] };

/* Function to check if builderId already exists */
const isBuilderIdExists = (currentBuilders: AppBuilderData[], builderId: string): boolean => {
return currentBuilders.some((builder) => builder.builderId === builderId);
};

/* Function to check if the same data exists globally */
const isDataExistsGlobally = (currentBuilders: AppBuilderData[], builderData: any): boolean => {
return currentBuilders.some((builder) => {
const existingBuilderData = builder.getBuilderData();

if (!existingBuilderData) return false;
return existingBuilderData.some(
(existingData) =>
existingData.id === builderData.id && existingData.name === builderData.name
);
});
};

/* Function to handle adding builder data to state */
const handleAddBuilderData = (state: BuilderState, action: any): BuilderState => {
const { data, builderData } = action.payload;

const currentBuilders = state.appBuilderData.map((builder) =>
recreateBuilderInstance(builder)
);

if (isBuilderIdExists(currentBuilders, data.builderId)) {
// eslint-disable-next-line no-console
console.warn(`Duplicate builderId detected: ${data.builderId}`);
return state;
}

if (isDataExistsGlobally(currentBuilders, builderData)) {
// eslint-disable-next-line no-console
console.warn(`Duplicate data detected for id: ${builderData.id} and name: ${builderData.name}`);
return state;
}

const updatedViewers = updateViewerContent(data.viewers, builderData);

data.setBuilderData([builderData]);

return {
...state,
appBuilderData: [
...state.appBuilderData,
{
...data,
viewers: updatedViewers, // Update viewers with the new content
},
],
};
};

const handleAddAttribute = (state: BuilderState, action: any): BuilderState => {
const { builderId, attributeData } = action.payload;

return {
...state,
appBuilderData: state.appBuilderData.map((builder) => {
// Only update the specified builder
if (builder.builderId !== builderId) {
return builder;
}

const newBuilder = recreateBuilderInstance(builder);
const viewers = newBuilder.getViewers();
const updatedViewers = updateViewers(viewers, [new FormattedAttribute(attributeData)]);

newBuilder.setViewers(updatedViewers);

return newBuilder;
})
};
};

const handleUpdateSelectedAttribute = (state: BuilderState, action: any): BuilderState => {
const { id } = action.payload;

return {
...state,
appBuilderData: state.appBuilderData.map((builder) => {
const newBuilder = recreateBuilderInstance(builder);
const viewers = newBuilder.getViewers();

const updatedViewers = viewers.map((viewer) => {
const currentContent = viewer.getViewerContent();

// Ensure content is an array and map over it
if (Array.isArray(currentContent)) {
const updatedContent = currentContent.map((attribute: any) => ({
...attribute,
attributeSelected: attribute.id === id, // Set true for selected, false for others
}));

viewer.setViewerContent(updatedContent);
}
return viewer;
});

newBuilder.setViewers(updatedViewers);
return newBuilder;
}),
};
};

const builderOptions = (state = initialState, action: any): BuilderState => {
switch (action.type) {
case ADD_APP_BUILDER_DATA_TO_REDUCER:
return handleAddBuilderData(state, action);

case ADD_ATTRIBUTE:
return handleAddAttribute(state, action);

case UPDATE_ATTRIBUTE_SELECTED_PROPS:
return handleUpdateSelectedAttribute(state, action);

case SET_BUILDER_DATA:
return {
...state,
appBuilderData: action.payload.appBuilderData,
};

default:
return state;
}
Expand Down
5 changes: 4 additions & 1 deletion app/types/builder.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ export const BUILDER_HISTORY = "BUILDER_HISTORY";
export const ADD_APP_BUILDER_DATA_TO_REDUCER = "ADD_APP_BUILDER_DATA_TO_REDUCER";
export const ADD_ATTRIBUTE = "ADD_ATTRIBUTE";
export const UPDATE_ATTRIBUTE_SELECTED_PROPS = "UPDATE_ATTRIBUTE_SELECTED_PROPS";
export const SET_TOOLBOX_DATA_TO_REDUCER = "SET_TOOLBOX_DATA_TO_REDUCER";
export const SET_TOOLBOX_DATA_TO_REDUCER = "SET_TOOLBOX_DATA_TO_REDUCER";

export const BUILDER_DATA_CASE_1 = "BUILDER_DATA_CASE_1";
export const SET_BUILDER_DATA = "SET_BUILDER_DATA";

0 comments on commit 00a7624

Please sign in to comment.