Skip to content

Commit 1faaba8

Browse files
authored
Merge pull request #28 from oslabs-beta/context-ui
Added error/confirmation messages
2 parents ce9a9d4 + 8c6e801 commit 1faaba8

File tree

4 files changed

+102
-154
lines changed

4 files changed

+102
-154
lines changed

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

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,21 @@ import Grid from '@mui/material/Grid';
44
import DataTable from './components/DataTable';
55
import AddDataForm from './components/AddDataForm';
66
import AddContextForm from './components/AddContextForm';
7-
// import * as actions from '../../../redux/actions/actions';
87
import { Typography } from '@mui/material';
98
import {
109
addContext,
1110
deleteContext,
1211
addContextValues
1312
} from '../../../redux/reducers/slice/contextReducer';
1413
import { useSelector, useDispatch } from 'react-redux';
15-
import { deleteElement } from '../../../redux/reducers/slice/appStateSlice';
1614
import { RootState } from '../../../redux/store';
1715

1816
const CreateContainer = () => {
1917
const state = useSelector((store: RootState) => store.contextSlice);
2018
const [contextInput, setContextInput] = React.useState(null);
2119
const [currentContext, setCurrentContext] = React.useState(null);
20+
const [errorMsg, setErrorMsg] = React.useState('');
21+
const [errorStatus, setErrorStatus] = React.useState(false);
2222
const currentKeyValues = state.allContext.find(
2323
(obj) => obj.name === currentContext
2424
)?.values || [{ key: 'Enter Key', value: 'Enter value' }];
@@ -27,50 +27,57 @@ const CreateContainer = () => {
2727
//update data store when user adds a new context
2828
const handleClickSelectContext = () => {
2929
//prevent user from adding duplicate context
30-
for (let i = 0; i < state.allContext.length; i += 1) {
31-
if (state.allContext[i].name === contextInput.name) {
32-
return;
33-
}
30+
let letters = /[a-zA-Z]/;
31+
let error;
32+
console.log(state.allContext, contextInput, 'error test');
33+
if (!contextInput || contextInput.trim() === '') {
34+
error = 'empty';
35+
} else if (!contextInput.charAt(0).match(letters)) {
36+
error = 'letters';
37+
} else if (!contextInput.match(/^[0-9a-zA-Z]+$/)) {
38+
error = 'symbolsDetected';
39+
} else if (
40+
state.allContext.some(
41+
(context) => context.name.toLowerCase() === contextInput.toLowerCase()
42+
)
43+
) {
44+
error = 'dupe';
45+
}
46+
47+
if (error !== undefined) {
48+
triggerError(error);
49+
return;
3450
}
51+
52+
dispatch(addContext({ name: contextInput }));
3553
setContextInput('');
36-
dispatch(addContext(contextInput));
54+
};
3755

38-
// setState(allContext);
56+
const triggerError = (type: String) => {
57+
setErrorStatus(true);
58+
if (type === 'empty') {
59+
setErrorMsg('Context name cannot be blank.');
60+
} else if (type === 'dupe') {
61+
setErrorMsg('Context name already exists.');
62+
} else if (type === 'letters') {
63+
setErrorMsg('Context name must start with a letter.');
64+
} else if (type === 'symbolsDetected') {
65+
setErrorMsg('Context name must not contain symbols.');
66+
}
3967
};
4068

4169
//update data store when user add new key-value pair to context
4270
const handleClickInputData = (name, { inputKey, inputValue }) => {
4371
dispatch(addContextValues({ name, inputKey, inputValue }));
44-
// setState(allContext);
4572
};
4673

4774
//update data store when user deletes context
4875
const handleDeleteContextClick = () => {
49-
dispatch(deleteContext(contextInput));
76+
dispatch(deleteContext({ name: currentContext }));
5077
setContextInput('');
51-
// setState(allContext);
52-
setTableState(defaultTableData);
53-
54-
dispatch(deleteElement({ id: 'FAKE_ID', contextParam: state }));
55-
// dispatchContext({
56-
// type: 'DELETE ELEMENT',
57-
// payload: 'FAKE_ID'
58-
// });
78+
setCurrentContext(null);
5979
};
6080

61-
//re-render data table when there's new changes
62-
const renderTable = (targetContext) => {
63-
if (
64-
targetContext === null ||
65-
targetContext === undefined ||
66-
!targetContext.values
67-
) {
68-
// if (targetContext === null || targetContext === undefined) {
69-
setTableState(defaultTableData);
70-
} else {
71-
setTableState(targetContext.values);
72-
}
73-
};
7481
console.log('state.allContext', state.allContext);
7582
return (
7683
<>
@@ -89,19 +96,20 @@ const CreateContainer = () => {
8996
contextStore={state}
9097
handleClickSelectContext={handleClickSelectContext}
9198
handleDeleteContextClick={handleDeleteContextClick}
92-
renderTable={renderTable}
9399
contextInput={contextInput}
94100
setContextInput={setContextInput}
95101
currentContext={currentContext}
96102
setCurrentContext={setCurrentContext}
103+
errorStatus={errorStatus}
104+
setErrorStatus={setErrorStatus}
105+
errorMsg={errorMsg}
97106
/>
98107
</Grid>
99108

100109
<Divider variant="middle" />
101110
<Grid item>
102111
<AddDataForm
103112
handleClickInputData={handleClickInputData}
104-
contextInput={contextInput}
105113
currentContext={currentContext}
106114
/>
107115
</Grid>

app/src/components/ContextAPIManager/CreateTab/components/AddContextForm.tsx

Lines changed: 61 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,66 @@
11
import React, { Fragment, useState } from 'react';
22
import TextField from '@mui/material/TextField';
33
import Select from '@mui/material/Select';
4-
import FormControl from '@mui/material/FormControl';
5-
import { createFilterOptions } from '@mui/material/Autocomplete';
4+
import Snackbar from '@mui/material/Snackbar';
65
import Button from '@mui/material/Button';
76
import Box from '@mui/material/Box';
7+
import IconButton from '@mui/material/IconButton';
8+
import CloseIcon from '@mui/icons-material/Close';
9+
import MuiAlert, { AlertProps } from '@mui/material/Alert';
810
import { MenuItem, Typography } from '@mui/material';
911
import { useSelector } from 'react-redux';
1012
import { RootState } from '../../../../redux/store';
11-
import { error } from 'console';
12-
13-
const filter = createFilterOptions();
1413

1514
const AddContextForm = ({
1615
contextStore,
1716
handleClickSelectContext,
1817
handleDeleteContextClick,
19-
renderTable,
2018
contextInput,
2119
setContextInput,
2220
currentContext,
23-
setCurrentContext
21+
setCurrentContext,
22+
errorMsg,
23+
errorStatus,
24+
setErrorStatus
2425
}) => {
2526
const { allContext } = contextStore;
2627
console.log('all contexts', allContext);
2728
const [btnDisabled, setBtnDisabled] = useState(false);
29+
const [open, setOpen] = useState(false);
2830
const { state, isDarkMode } = useSelector((store: RootState) => ({
2931
isDarkMode: store.darkMode.isDarkMode,
3032
state: store.appState
3133
}));
3234
const color = isDarkMode ? 'white' : 'black';
33-
const [selection, setSelection] = React.useState('');
3435

3536
const handleClick = () => {
36-
if (contextInput === '' || contextInput === null) {
37-
window.alert('must enter context name');
38-
return;
39-
}
4037
handleClickSelectContext();
38+
setOpen(true);
4139
};
4240

43-
// const onChange = (event, newValue) => {
44-
// if (typeof newValue === 'string') {
45-
// setContextInput({
46-
// name: newValue
47-
// });
48-
// } else if (newValue && newValue.inputValue) {
49-
// // Create a new contextInput from the user input
50-
// setContextInput({
51-
// name: newValue.inputValue,
52-
// values: []
53-
// });
54-
// renderTable(newValue);
55-
// } else {)
56-
// setContextInput(newValue);
57-
// renderTable(newValue);
58-
// }
59-
// };
60-
6141
const handleChange = (e) => {
62-
setContextInput({ name: e.target.value });
42+
setErrorStatus(false);
43+
setOpen(false);
44+
setContextInput(e.target.value);
6345
};
6446

65-
const filterOptions = (options, params) => {
66-
// setBtnDisabled(true);
67-
const filtered = filter(options, params);
68-
const { inputValue } = params;
69-
// Suggest the creation of a new contextInput
70-
const isExisting = options.some((option) => inputValue === option.name);
71-
if (inputValue !== '' && !isExisting) {
72-
filtered.push({
73-
inputValue,
74-
name: `Add "${inputValue}"`
75-
});
76-
77-
// setBtnDisabled(false);
47+
const handleClose = (
48+
event: React.SyntheticEvent | Event,
49+
reason?: string
50+
) => {
51+
if (reason === 'clickaway') {
52+
return;
7853
}
7954

80-
return filtered;
81-
};
82-
83-
const getOptionLabel = (option) => {
84-
// Value selected with enter, right from the input
85-
if (typeof option === 'string') {
86-
return option;
87-
}
88-
// Add "xxx" option created dynamically
89-
if (option.inputValue) {
90-
return option.inputValue;
91-
}
92-
// Regular option
93-
return option.name;
55+
setOpen(false);
9456
};
9557

96-
const renderOption = (props, option) => (
97-
<li style={{ color: 'black' }} {...props}>
98-
{option.name}
99-
</li>
100-
);
58+
const Alert = React.forwardRef<HTMLDivElement, AlertProps>(function Alert(
59+
props,
60+
ref
61+
) {
62+
return <MuiAlert elevation={6} ref={ref} variant="filled" {...props} />;
63+
});
10164

10265
const contexts = allContext.map((context) => {
10366
return (
@@ -113,56 +76,59 @@ const AddContextForm = ({
11376
Create Context
11477
</Typography>
11578
<Box sx={{ display: 'flex', gap: 2, mb: 4 }}>
116-
{/* <Autocomplete
117-
id="autoCompleteContextField"
118-
value={contextInput}
119-
onChange={onChange}
120-
filterOptions={filterOptions}
121-
selectOnFocus
122-
clearOnBlur
123-
handleHomeEndKeys
124-
options={allContext || []}
125-
getOptionLabel={getOptionLabel}
126-
renderOption={renderOption}
127-
sx={{ width: 425, border: '1px solid black' }}
128-
freeSolo
129-
renderInput={(params) => (
130-
<TextField
131-
{...params}
132-
InputProps={{
133-
...params.InputProps,
134-
style: { color: color }
135-
}}
136-
variant="filled"
137-
label="Create/Select Context"
138-
/>
139-
)}
140-
/> */}
14179
<TextField
14280
InputProps={{
14381
style: { color: 'black' }
14482
}}
145-
// {...params}
146-
// InputProps={{
147-
// ...params.InputProps,
148-
// style: { color: color }
149-
// }}
15083
onChange={handleChange}
15184
sx={{
15285
width: 425,
153-
border: '1px solid black',
154-
color: 'black !important'
86+
border: '1px solid black'
15587
}}
15688
variant="filled"
15789
label="Create Context"
90+
value={contextInput}
91+
helperText={errorStatus ? errorMsg : null}
92+
error={errorStatus}
15893
/>
94+
<Snackbar
95+
open={open && !errorStatus}
96+
autoHideDuration={6000}
97+
onClose={handleClose}
98+
>
99+
<Alert
100+
onClose={handleClose}
101+
severity="success"
102+
sx={{ width: '100%', color: 'white' }}
103+
>
104+
Context Created
105+
</Alert>
106+
</Snackbar>
159107
<Button
160108
variant="contained"
161109
onClick={handleClick}
162110
disabled={btnDisabled}
163111
>
164112
Create
165113
</Button>
114+
</Box>
115+
<Typography style={{ color: color }} variant="h6" gutterBottom={true}>
116+
Select Context
117+
</Typography>
118+
<Box sx={{ display: 'flex', gap: 2, mb: 4 }}>
119+
<Select
120+
sx={{ width: 425 }}
121+
style={{ border: '1px solid #0099e6', color: 'black' }}
122+
value={currentContext}
123+
label="Select Context"
124+
MenuProps={{ disablePortal: true }}
125+
onChange={(e) => {
126+
console.log(e);
127+
setCurrentContext(e.target.value);
128+
}}
129+
>
130+
{contexts}
131+
</Select>
166132
<Button
167133
color="error"
168134
variant="contained"
@@ -171,25 +137,6 @@ const AddContextForm = ({
171137
Delete
172138
</Button>
173139
</Box>
174-
<Typography style={{ color: color }} variant="h6" gutterBottom={true}>
175-
Select Context
176-
</Typography>
177-
178-
<Select
179-
style={{ border: '1px solid #0099e6', color: 'black' }}
180-
value={currentContext}
181-
label="Select Context"
182-
MenuProps={{ disablePortal: true }}
183-
onChange={(e) => {
184-
console.log(e);
185-
setCurrentContext(e.target.value);
186-
}}
187-
188-
// value={props.selectValue}
189-
// onChange={props.handleChange}
190-
>
191-
{contexts}
192-
</Select>
193140
</Fragment>
194141
);
195142
};

app/src/components/ContextAPIManager/CreateTab/components/AddDataForm.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { RootState } from '../../../../redux/store';
88

99
const AddDataForm = ({
1010
handleClickInputData,
11-
contextInput,
1211
currentContext
1312
}) => {
1413
//const [contextInput, setContextInput] = React.useState(null);

0 commit comments

Comments
 (0)