Skip to content

Commit 210b3df

Browse files
authored
Merge pull request #8 from oslabs-beta/disableUseState
Disable use state
2 parents b56f039 + 2cecae0 commit 210b3df

File tree

13 files changed

+241
-67
lines changed

13 files changed

+241
-67
lines changed

app/src/components/StateManagement/CreateTab/CreateContainer.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
import React, { useEffect, useState, useContext } from 'react';
22
import { useStore } from 'react-redux';
33
import { useDispatch } from 'react-redux';
4-
import Divider from '@mui/material/Divider';
54
import Grid from '@mui/material/Grid';
6-
import DataTable from './components/DataTable';
75
import * as actions from '../../../redux/actions/actions';
8-
import { Typography } from '@mui/material';
96
import StateContext from '../../../context/context';
107
import StatePropsPanel from './components/StatePropsPanel';
11-
import TableStateProps from './components/TableStateProps';
128

139
//LegacyPD added this in here
1410
//import StatePropsPanel from '../../right/StatePropsPanel';

app/src/components/StateManagement/CreateTab/components/StatePropsPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ const StatePropsPanel = ({ isThemeLight, data}): JSX.Element => {
204204
/>
205205
<TextField
206206
id="textfield-value"
207-
label="value:"
207+
label="initial value:"
208208
variant="outlined"
209209
value={inputValue}
210210
onChange={(e) => setInputValue(e.target.value)}

app/src/components/StateManagement/CreateTab/components/TableParentProps.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ const TableParentProps = props => {
3737
},
3838
{
3939
field: 'value',
40-
headerName: 'Value',
41-
width: 90,
40+
headerName: 'Initial Value',
41+
width: 100,
4242
editable: true
4343
},
4444
{

app/src/components/StateManagement/CreateTab/components/TablePassedInProps.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ const TablePassedInProps = props => {
3535
},
3636
{
3737
field: 'value',
38-
headerName: 'Value',
39-
width: 90,
38+
headerName: 'Initial Value',
39+
width: 100,
4040
editable: true
4141
},
4242
{

app/src/components/StateManagement/CreateTab/components/TableStateProps.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ const TableStateProps = props => {
3434
},
3535
{
3636
field: 'value',
37-
headerName: 'Value',
38-
width: 90,
37+
headerName: 'Initial Value',
38+
width: 100,
3939
editable: true
4040
},
4141
{

app/src/components/StateManagement/DisplayTab/DataTable.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,19 @@ const StyledTableRow = styled(TableRow)(({ theme }) => ({
3131
}));
3232

3333
export default function DataTable(props) {
34-
const { currComponentState, setCurrComponentState, parentProps, setParentProps, clickedComp } = props;
34+
const { currComponentState, setCurrComponentState, parentProps, setParentProps, clickedComp, data } = props;
35+
const [state, dispatch] = useContext(StateContext);
36+
37+
//determine if the current component is a root component
38+
let isRoot = false;
39+
40+
//iterate through the data array and see if clickedComp is in state.rootComponents
41+
for (let i = 0; i < data.length; i++) {
42+
if (data[i]['name'] === clickedComp) {
43+
//check to see if clickedComp is in rootComponents
44+
if (state.rootComponents.includes(data[i]['id'])) isRoot = true;
45+
}
46+
}
3547

3648
return (
3749
<>
@@ -43,8 +55,8 @@ export default function DataTable(props) {
4355
>
4456

4557
{/* this table will contain passed down stateProps data from parent component */}
46-
{/* we are checking if the clicked component is App-- if it is App, it doesn't have any parents so don't need this table*/}
47-
{(clickedComp !== 'App' &&
58+
{/* we are checking if the clicked component is a root component-- if it is, it doesn't have any parents so don't need this table*/}
59+
{(!isRoot &&
4860
<>
4961
<TableHead>
5062
<TableRow>

app/src/components/StateManagement/DisplayTab/DisplayContainer.tsx

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {useState, useContext} from 'react';
1+
import React, {useState, useContext, useEffect} from 'react';
22
import Tree from './Tree';
33
import Divider from '@mui/material/Divider';
44
import Grid from '@mui/material/Grid';
@@ -12,22 +12,42 @@ function DisplayContainer({data, props}) { // "data" is referring to components
1212
const [currComponentState, setCurrComponentState] = useState([]);
1313
const [parentProps, setParentProps] = useState([]);
1414
const [state, dispatch] = useContext(StateContext);
15+
16+
let root = '';
1517

16-
17-
// check projectType. If it's 'Classic React', title should read 'App'. Otherwise it's Next.js or Gatsby which uses 'index'
18-
let root;
19-
if (state.projectType === "Classic React") {
18+
// check the canvasFocus
19+
// if canvasFocus is a root component, use that root component as "root"
20+
if (state.rootComponents.includes(state.canvasFocus.componentId)) {
21+
//find the name of the canvasFocus component in data
22+
//set root equal to that name
23+
// iterate through data (which is an array of objects)
24+
for (let i = 0; i < data.length; i++) {
25+
// find object with id that is equal to state.canvasFocus.componentId
26+
// then set root equal to the name of that component
27+
if (data[i]["id"] === state.canvasFocus.componentId) root = data[i]["name"];
28+
}
29+
} else if (state.projectType === "Classic React") {
30+
// else default to the main root component (aka app or index depending on react vs next/gatsby)
2031
root = 'App';
21-
} else {
32+
} else {
2233
root = 'index';
23-
}
34+
}
35+
2436
const [clickedComp, setClickedComp] = useState(root);
2537

2638
return (
2739
<div style={{display: 'flex'}}>
28-
{<Tree data = {data} currComponentState={currComponentState} setCurrComponentState ={setCurrComponentState} parentProps={parentProps} setParentProps={setParentProps} setClickedComp={setClickedComp} />}
40+
{<Tree data = {data} currComponentState={currComponentState} setCurrComponentState ={setCurrComponentState} parentProps={parentProps} setParentProps={setParentProps} setClickedComp={setClickedComp}/>}
2941
<Divider orientation="vertical" variant="middle" flexItem />
3042
<Grid item>
43+
<Typography
44+
style={{ color: 'black' }}
45+
variant="subtitle2"
46+
gutterBottom={true}
47+
align="center"
48+
>
49+
Click on a component in the graph to see its state!
50+
</Typography>
3151
<Typography
3252
style={{ color: 'black' }}
3353
variant="h6"
@@ -36,7 +56,7 @@ function DisplayContainer({data, props}) { // "data" is referring to components
3656
>
3757
Total State for {clickedComp}
3858
</Typography>
39-
<DataTable currComponentState={currComponentState} setCurrComponentState ={setCurrComponentState} parentProps={parentProps} setParentProps={setParentProps} props={props} clickedComp={clickedComp} />
59+
<DataTable currComponentState={currComponentState} setCurrComponentState ={setCurrComponentState} parentProps={parentProps} setParentProps={setParentProps} props={props} clickedComp={clickedComp} data = {data} />
4060
</Grid>
4161
</div>
4262
);

app/src/components/StateManagement/DisplayTab/Tree.tsx

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useRef, useEffect, useContext } from 'react';
1+
import React, { useRef, useEffect, useContext, useState } from 'react';
22
import { select, hierarchy, tree, linkHorizontal} from 'd3';
33
import cloneDeep from 'lodash/cloneDeep';
44
import useResizeObserver from './useResizeObserver';
@@ -10,7 +10,7 @@ function usePrevious(value) {
1010
return ref.current;
1111
}
1212

13-
function Tree({ data, currComponentState, setCurrComponentState, parentProps, setParentProps, setClickedComp }) {
13+
function Tree({ data, currComponentState, setCurrComponentState, parentProps, setParentProps, setClickedComp}) {
1414
const [state, dispatch] = useContext(StateContext);
1515
const svgRef = useRef();
1616
const wrapperRef = useRef();
@@ -41,7 +41,6 @@ function Tree({ data, currComponentState, setCurrComponentState, parentProps, se
4141
// create a deep clone of data to avoid mutating the actual children array in removing separators
4242
const dataDeepClone = cloneDeep(data);
4343

44-
// LEGACYPD to look at when trying to figure out how to convert tab to work for NextJS
4544
if(state.projectType === 'Next.js') {
4645
dataDeepClone.forEach(element => {
4746
element.children = sanitize(element.children).filter(element => !Array.isArray(element));
@@ -57,7 +56,7 @@ function Tree({ data, currComponentState, setCurrComponentState, parentProps, se
5756

5857
// remove separators and update components to current versions
5958
dataDeepClone.forEach(component => removeHTMLElements(component.children));
60-
59+
6160
// will be called initially and on every data change
6261
useEffect(() => {
6362
const svg = select(svgRef.current);
@@ -66,7 +65,31 @@ function Tree({ data, currComponentState, setCurrComponentState, parentProps, se
6665
// (dimensions are null for the first render)
6766
const { width, height } = dimensions || wrapperRef.current.getBoundingClientRect();
6867
// transform hierarchical data
69-
const root = hierarchy(dataDeepClone[0]);
68+
69+
let root;
70+
let rootName;
71+
72+
if (state.rootComponents.includes(state.canvasFocus.componentId)) {
73+
// find out if canvasFocus is a root component
74+
// if yes, set root to be that canvasFocus component
75+
// find that component inside dataDeepClone
76+
for (let i = 0; i < dataDeepClone.length; i++) {
77+
if (dataDeepClone[i]['id'] === state.canvasFocus.componentId) {
78+
// reassign root to be dataDeepClone at that element
79+
80+
root = hierarchy(dataDeepClone[i]);
81+
rootName = dataDeepClone[i]["name"];
82+
83+
}
84+
}
85+
} else {
86+
// if no, set root to be dataDeepClone[0]
87+
root = hierarchy(dataDeepClone[0]);
88+
rootName = dataDeepClone[0]["name"];
89+
}
90+
91+
setClickedComp(rootName);
92+
7093
const treeLayout = tree().size([height, width - 125]);
7194
// Returns a new link generator with horizontal display.
7295
// To visualize links in a tree diagram rooted on the left edge of the display
@@ -76,7 +99,7 @@ function Tree({ data, currComponentState, setCurrComponentState, parentProps, se
7699

77100
// insert our data into the tree layout
78101
treeLayout(root);
79-
102+
80103
svg
81104
.selectAll('.node')
82105
.data(root.descendants())
@@ -99,7 +122,7 @@ function Tree({ data, currComponentState, setCurrComponentState, parentProps, se
99122
let passedInProps;
100123
let componentStateProps;
101124

102-
// iterate through data array to find stateProps for parent and clicked element
125+
// iterate through data array to find stateProps and passedInProps
103126
for(let i = 0; i < data.length; i++) {
104127
if(data[i]["name"] === nameOfClicked) {
105128
componentStateProps = data[i]["stateProps"];
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
2+
import React, { useState, useContext, useEffect } from 'react';
3+
import {
4+
DataGrid,
5+
GridEditRowsModel,
6+
} from '@mui/x-data-grid';
7+
import Button from '@material-ui/core/Button';
8+
import ClearIcon from '@material-ui/icons/Clear';
9+
import StateContext from '../../context/context';
10+
import { makeStyles } from '@material-ui/core/styles';
11+
import { StatePropsPanelProps } from '../../interfaces/Interfaces';
12+
13+
const TableStateProps = props => {
14+
const [state, dispatch] = useContext(StateContext);
15+
const classes = useStyles();
16+
const [editRowsModel] = useState<GridEditRowsModel>({});
17+
const [gridColumns, setGridColumns] = useState([]);
18+
const columnTabs = [
19+
{
20+
field: 'id',
21+
headerName: 'ID',
22+
width: 70,
23+
editable: false
24+
},
25+
{
26+
field: 'key',
27+
headerName: 'Key',
28+
width: 90,
29+
editable: true
30+
},
31+
{
32+
field: 'value',
33+
headerName: 'Initial Value',
34+
width: 100,
35+
editable: true
36+
},
37+
{
38+
field: 'type',
39+
headerName: 'Type',
40+
width: 90,
41+
editable: false
42+
},
43+
{
44+
field: 'delete',
45+
headerName: 'X',
46+
width: 70,
47+
editable: false,
48+
renderCell: function renderCell(params: any) {
49+
return (
50+
<Button
51+
style={{ width: `${3}px` }}
52+
onClick={() => {
53+
deleteState(params.id);
54+
}}
55+
>
56+
<ClearIcon style={{ width: `${15}px` }} />
57+
</Button>
58+
);
59+
}
60+
}
61+
];
62+
const deleteState = selectedId => {
63+
// get the current focused component
64+
// remove the state that the button is clicked
65+
// send a dispatch to rerender the table
66+
const currentId = state.canvasFocus.componentId;
67+
const currentComponent = state.components[currentId - 1];
68+
const filtered = currentComponent.stateProps.filter(
69+
element => element.id !== selectedId
70+
);
71+
dispatch({
72+
type: 'DELETE STATE',
73+
payload: { stateProps: filtered, rowId: selectedId }
74+
});
75+
};
76+
77+
useEffect(() => {
78+
setGridColumns(columnTabs);
79+
}, [props.isThemeLight]);
80+
81+
const { selectHandler }: StatePropsPanelProps = props;
82+
// the delete button needs to be updated to remove
83+
// the states from the current focused component
84+
useEffect(() => {
85+
if (props.canDeleteState) {
86+
setGridColumns(columnTabs);
87+
} else {
88+
setGridColumns(columnTabs.slice(0, gridColumns.length - 1));
89+
}
90+
}, [state.canvasFocus.componentId]);
91+
92+
// create rows to show the current component's state props
93+
let rows = [];
94+
const currentId = state.canvasFocus.componentId;
95+
const currentComponent = state.components[currentId - 1];
96+
let currentProps = currentComponent.stateProps.slice();
97+
98+
//add in passed in props for the current component (if it is not a root component)
99+
if (currentComponent.name !== 'App' && currentComponent.name !== 'index') {
100+
let propsPassed = currentComponent.passedInProps?.slice();
101+
for (let i = 0; i < propsPassed.length; i++) {
102+
currentProps.push(propsPassed[i]);
103+
}
104+
}
105+
rows = currentProps;
106+
107+
return (
108+
<div className={'state-prop-grid'}>
109+
<DataGrid
110+
rows={rows}
111+
columns={gridColumns}
112+
pageSize={5}
113+
editRowsModel={editRowsModel}
114+
onRowClick={selectHandler}
115+
className={props.isThemeLight ? classes.themeLight : classes.themeDark}
116+
/>
117+
</div>
118+
);
119+
};
120+
121+
const useStyles = makeStyles({
122+
themeLight: {
123+
color: 'rgba(0,0,0,0.54)',
124+
'& .MuiTablePagination-root': {
125+
color: 'rbga(0,0,0,0.54)'
126+
}
127+
},
128+
themeDark: {
129+
color: 'white',
130+
'& .MuiTablePagination-root': {
131+
color: 'white'
132+
},
133+
'& .MuiIconButton-root': {
134+
color: 'white'
135+
},
136+
'& .MuiSvgIcon-root': {
137+
color: 'white'
138+
},
139+
'& .MuiDataGrid-window': {
140+
backgroundColor: 'rgba(0,0,0,0.54)'
141+
}
142+
}
143+
});
144+
145+
export default TableStateProps;

0 commit comments

Comments
 (0)