FieldList.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. import React, { useEffect, useRef } from 'react';
  2. import PropTypes from 'prop-types';
  3. import {
  4. TextField,
  5. Grid,
  6. InputBase,
  7. Button,
  8. NativeSelect,
  9. Box,
  10. Typography
  11. } from '@material-ui/core';
  12. import { withStyles, makeStyles } from '@material-ui/core/styles';
  13. import SaveIcon from '@material-ui/icons/Save';
  14. import CancelIcon from '@material-ui/icons/Cancel';
  15. const BootstrapInput = withStyles((theme) => ({
  16. root: {
  17. 'label + &': {
  18. marginTop: theme.spacing(3),
  19. },
  20. },
  21. input: {
  22. borderRadius: 4,
  23. position: 'relative',
  24. backgroundColor: 'transparent',
  25. border: '1px solid #ced4da',
  26. fontSize: 16,
  27. padding: '10px 26px 10px 12px',
  28. transition: theme.transitions.create(['border-color', 'box-shadow']),
  29. // Use the system font instead of the default Roboto font.
  30. fontFamily: [
  31. '-apple-system',
  32. 'BlinkMacSystemFont',
  33. '"Segoe UI"',
  34. 'Roboto',
  35. '"Helvetica Neue"',
  36. 'Arial',
  37. 'sans-serif',
  38. '"Apple Color Emoji"',
  39. '"Segoe UI Emoji"',
  40. '"Segoe UI Symbol"',
  41. ].join(','),
  42. '&:focus': {
  43. borderRadius: 4,
  44. borderColor: '#80bdff',
  45. boxShadow: '0 0 0 0.2rem rgba(0,123,255,.25)',
  46. },
  47. },
  48. }))(InputBase);
  49. const useStyles = makeStyles((theme) => ({
  50. root: {
  51. width: '100%',
  52. },
  53. paper: {
  54. width: '100%',
  55. marginBottom: theme.spacing(2),
  56. },
  57. table: {
  58. minWidth: 750,
  59. },
  60. visuallyHidden: {
  61. border: 0,
  62. clip: 'rect(0 0 0 0)',
  63. height: 1,
  64. margin: -1,
  65. overflow: 'hidden',
  66. padding: 0,
  67. position: 'absolute',
  68. top: 20,
  69. width: 1,
  70. },
  71. underline: {
  72. "&&&:before": {
  73. borderBottom: "none"
  74. },
  75. "&&:after": {
  76. borderBottom: "none"
  77. }
  78. }
  79. }));
  80. function FieldList(props) {
  81. const classes = useStyles();
  82. const {
  83. fields = [],
  84. updateData = {},
  85. onDataCallback
  86. } = props;
  87. const [data, setDataField] = React.useState(updateData != undefined ? updateData : {});
  88. const [imgPreview, setImgPreviewPath] = React.useState(null);
  89. const handleTextString = (e, fieldName) => {
  90. setDataField({ ...data, [fieldName]: e.target.value });
  91. }
  92. const handleTextNumber = (e, fieldName) => {
  93. setDataField({ ...data, [fieldName]: e.target.value });
  94. }
  95. const handleTextMultiline = (e, fieldName) => {
  96. setDataField({ ...data, [fieldName]: e.target.value });
  97. }
  98. const handleDate = (e, fieldName) => {
  99. setDataField({ ...data, [fieldName]: e.target.value });
  100. }
  101. const handleDropDownChange = (e, fieldName) => {
  102. var selectedIndex = e.target.options.selectedIndex;
  103. var selectedValue = e.target.options[selectedIndex].getAttribute('name');
  104. var fn = fieldName.split('_');
  105. var fieldId = fn[0] + '_' + 'id';
  106. setDataField({ ...data, [fieldName]: selectedValue, [fieldId]: e.target.value });
  107. }
  108. const handleImgUpload = (e, fieldName) => {
  109. e.preventDefault();
  110. let reader = new FileReader();
  111. let file = e.target.files[0];
  112. reader.onloadend = () => {
  113. setImgPreviewPath(reader.result);
  114. }
  115. reader.readAsDataURL(file);
  116. setDataField({ ...data, [fieldName]: e.target.files[0].name });
  117. }
  118. const handleDataConfirm = () => {
  119. onDataCallback(data);
  120. }
  121. return (
  122. <div className={classes.root}>
  123. <Grid container>
  124. <Grid item xs={11}>
  125. {fields.map((f, i) => {
  126. if (f.type == 'text_string') {
  127. return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
  128. <Grid item xs={12} sm={5}>
  129. <Box style={{ width: '150px' }}>
  130. <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
  131. </Box>
  132. </Grid>
  133. <Grid item xs={12} sm={7}>
  134. <TextField id={f.fieldName}
  135. variant="outlined"
  136. autoComplete="off"
  137. size={"small"}
  138. style={{ width: '100%' }}
  139. value={data != undefined ? data[f.fieldName] : null}
  140. onChange={(e) => handleTextString(e, f.fieldName)}
  141. />
  142. </Grid>
  143. </Grid>;
  144. }
  145. else if (f.type == 'text_number') {
  146. return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
  147. <Grid item xs={12} sm={5}>
  148. <Box style={{ width: '150px' }}>
  149. <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
  150. </Box>
  151. </Grid>
  152. <Grid item xs={12} sm={7}>
  153. <TextField
  154. id={f.fieldName}
  155. variant="outlined"
  156. autoComplete="off"
  157. size={"small"}
  158. style={{ width: '100%' }}
  159. type="number"
  160. value={data != undefined ? data[f.fieldName] : ''}
  161. // onChange={handleTextNumber}
  162. onChange={(e) => handleTextNumber(e, f.fieldName)}
  163. />
  164. </Grid>
  165. </Grid>;
  166. }
  167. else if (f.type == 'text_multiline') {
  168. return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
  169. <Grid item xs={12} sm={5}>
  170. <Box style={{ width: '150px' }}>
  171. <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
  172. </Box>
  173. </Grid>
  174. <Grid item xs={12} sm={7}>
  175. <TextField
  176. id={f.fieldName}
  177. multiline
  178. autoComplete="off"
  179. rows={3}
  180. size={"small"}
  181. style={{ width: '100%' }}
  182. value={data != undefined ? data[f.fieldName] : ''}
  183. variant="outlined"
  184. onChange={(e) => handleTextMultiline(e, f.fieldName)}
  185. />
  186. </Grid>
  187. </Grid>;
  188. }
  189. else if (f.type == 'date') {
  190. return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
  191. <Grid item xs={12} sm={5}>
  192. <Box style={{ width: '150px' }}>
  193. <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
  194. </Box>
  195. </Grid>
  196. <Grid item xs={12} sm={7}>
  197. <TextField
  198. id={f.fieldName}
  199. variant="outlined"
  200. autoComplete="off"
  201. size={"small"}
  202. value={data != undefined ? data[f.fieldName] : ''}
  203. type="date"
  204. style={{ width: '100%' }}
  205. // onChange={handleDate}
  206. onChange={(e) => handleDate(e, f.fieldName)}
  207. />
  208. </Grid>
  209. </Grid>;
  210. }
  211. else if (f.type == 'photo') {
  212. return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
  213. <Grid item xs={12} sm={5}>
  214. <Box style={{ width: '150px' }}>
  215. <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
  216. </Box>
  217. </Grid>
  218. <Grid item xs={12} sm={7}>
  219. <img src={imgPreview == null ? data['photo_url'] : imgPreview} style={{ width: '120px', height: '120px', border: '1px solid grey' }}></img>
  220. <input type='file' id='img-upload' onChange={(e) => handleImgUpload(e, f.fieldName)}></input>
  221. </Grid>
  222. </Grid>;
  223. }
  224. else if (f.type == 'dropdown') {
  225. if (f.fieldName == 'priority') {
  226. return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
  227. <Grid item xs={12} sm={5}>
  228. <Box style={{ width: '150px' }}>
  229. <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
  230. </Box>
  231. </Grid>
  232. <Grid item xs={12} sm={7}>
  233. <NativeSelect
  234. id="demo-customized-select-native"
  235. value={data != undefined ? data[f.fieldName] : ''}
  236. onChange={(e) => handleDropDownChange(e, f.fieldName)}
  237. id={f.fieldName}
  238. input={<BootstrapInput />}
  239. style={{ width: '100%' }}
  240. >
  241. <option aria-label="None" value="" >Select</option>
  242. {f.options.map((d, i) => {
  243. return <option name={d.name} value={d.id}>{d.name}</option>;
  244. })}
  245. </NativeSelect>
  246. </Grid>
  247. </Grid>;
  248. } else {
  249. var fn = f.fieldName.split('_');
  250. var fieldId = fn[0] + '_' + 'id';
  251. return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
  252. <Grid item xs={12} sm={5}>
  253. <Box style={{ width: '150px' }}>
  254. <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
  255. </Box>
  256. </Grid>
  257. <Grid item xs={12} sm={7}>
  258. <NativeSelect
  259. id="demo-customized-select-native"
  260. value={data != undefined ? data[fieldId] : ''}
  261. onChange={(e) => handleDropDownChange(e, f.fieldName)}
  262. id={f.fieldName}
  263. input={<BootstrapInput />}
  264. style={{ width: '100%' }}
  265. >
  266. <option aria-label="None" value="" >Select</option>
  267. {f.options.map((d, i) => {
  268. return <option name={d.name} value={d.id}>{d.name}</option>;
  269. })}
  270. </NativeSelect>
  271. </Grid>
  272. </Grid>;
  273. }
  274. }
  275. else if (f.type == 'checkbox') {
  276. return <Grid></Grid>;
  277. }
  278. else if (f.type == 'radio') {
  279. return <Grid></Grid>;
  280. }
  281. })}
  282. </Grid>
  283. <Grid item xs={11}>
  284. <Box>
  285. <Button style={{ float: 'right' }}
  286. onClick={handleDataConfirm}
  287. > Confirm</Button>
  288. </Box>
  289. </Grid>
  290. </Grid>
  291. </div>
  292. );
  293. }
  294. FieldList.propTypes = {
  295. history: PropTypes.object,
  296. fields: PropTypes.array.isRequired,
  297. updateData: PropTypes.object,
  298. onDataCallback: PropTypes.func
  299. };
  300. export default (FieldList);