FieldEditor.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  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 FieldEditor(props) {
  81. const classes = useStyles();
  82. const { fields = [],
  83. currentTabName = "account",
  84. isNew = false,
  85. buttonColor = 'blue',
  86. updateData = {},
  87. onCreate,
  88. onUpdate,
  89. onInvite,
  90. onCancel,
  91. onApproved } = props;
  92. const [data, setDataField] = React.useState(updateData != undefined ? updateData : {});
  93. const [imgPreview, setImgPreviewPath] = React.useState(null);
  94. const handleTextString = (e, fieldName) => {
  95. if (isNew) {
  96. setDataField({ ...data, [fieldName]: e.target.value });
  97. } else {
  98. setDataField({ ...data, [fieldName]: e.target.value });
  99. }
  100. }
  101. const handleTextNumber = (e, fieldName) => {
  102. if (isNew) {
  103. setDataField({ ...data, [fieldName]: e.target.value });
  104. } else {
  105. setDataField({ ...data, [fieldName]: e.target.value });
  106. }
  107. }
  108. const handleTextMultiline = (e, fieldName) => {
  109. if (isNew) {
  110. setDataField({ ...data, [fieldName]: e.target.value });
  111. } else {
  112. setDataField({ ...data, [fieldName]: e.target.value });
  113. }
  114. }
  115. const handleDate = (e, fieldName) => {
  116. if (isNew) {
  117. setDataField({ ...data, [fieldName]: e.target.value });
  118. } else {
  119. setDataField({ ...data, [fieldName]: e.target.value });
  120. }
  121. }
  122. const handleDropDownChange = (e, fieldName) => {
  123. var selectedIndex = e.target.options.selectedIndex;
  124. var selectedValue = e.target.options[selectedIndex].getAttribute('name');
  125. var fn = fieldName.split('_');
  126. var fieldId = fn[0] + '_' + 'id';
  127. if (isNew) {
  128. setDataField({ ...data, [fieldName]: selectedValue, [fieldId]: e.target.value });
  129. } else {
  130. setDataField({ ...data, [fieldName]: selectedValue, [fieldId]: e.target.value });
  131. }
  132. }
  133. const handleSave = () => {
  134. if (isNew) {
  135. onCreate(data);
  136. } else {
  137. onUpdate(data);
  138. }
  139. }
  140. const handleApproved = () => {
  141. onApproved(data);
  142. }
  143. const handleCancel = () => {
  144. onCancel();
  145. }
  146. const handleInvite = () => {
  147. onInvite(data);
  148. }
  149. const handleImgUpload = (e, fieldName) => {
  150. e.preventDefault();
  151. let reader = new FileReader();
  152. let file = e.target.files[0];
  153. reader.onloadend = () => {
  154. setImgPreviewPath(reader.result);
  155. }
  156. reader.readAsDataURL(file);
  157. // setDataField({ ...data, [fieldName]: e.target.files[0].name });
  158. }
  159. console.log('file upload :', data);
  160. return (
  161. <div className={classes.root}>
  162. <Grid container>
  163. <Grid item xs={11}>
  164. {fields.map((f, i) => {
  165. if (f.type == 'text_string') {
  166. return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
  167. <Grid item xs={12} sm={5}>
  168. <Box style={{ width: '150px' }}>
  169. <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
  170. </Box>
  171. </Grid>
  172. <Grid item xs={12} sm={7}>
  173. <TextField id={f.fieldName}
  174. variant="outlined"
  175. autoComplete="off"
  176. size={"small"}
  177. style={{ width: '100%' }}
  178. value={data != undefined ? data[f.fieldName] : null}
  179. onChange={(e) => handleTextString(e, f.fieldName)}
  180. />
  181. </Grid>
  182. </Grid>;
  183. }
  184. else if (f.type == 'text_number') {
  185. return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
  186. <Grid item xs={12} sm={5}>
  187. <Box style={{ width: '150px' }}>
  188. <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
  189. </Box>
  190. </Grid>
  191. <Grid item xs={12} sm={7}>
  192. <TextField
  193. id={f.fieldName}
  194. variant="outlined"
  195. autoComplete="off"
  196. size={"small"}
  197. style={{ width: '100%' }}
  198. type="number"
  199. value={data != undefined ? data[f.fieldName] : ''}
  200. // onChange={handleTextNumber}
  201. onChange={(e) => handleTextNumber(e, f.fieldName)}
  202. />
  203. </Grid>
  204. </Grid>;
  205. }
  206. else if (f.type == 'text_multiline') {
  207. return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
  208. <Grid item xs={12} sm={5}>
  209. <Box style={{ width: '150px' }}>
  210. <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
  211. </Box>
  212. </Grid>
  213. <Grid item xs={12} sm={7}>
  214. <TextField
  215. id={f.fieldName}
  216. multiline
  217. autoComplete="off"
  218. rows={3}
  219. size={"small"}
  220. style={{ width: '100%' }}
  221. value={data != undefined ? data[f.fieldName] : ''}
  222. variant="outlined"
  223. onChange={(e) => handleTextMultiline(e, f.fieldName)}
  224. />
  225. </Grid>
  226. </Grid>;
  227. }
  228. else if (f.type == 'date') {
  229. return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
  230. <Grid item xs={12} sm={5}>
  231. <Box style={{ width: '150px' }}>
  232. <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
  233. </Box>
  234. </Grid>
  235. <Grid item xs={12} sm={7}>
  236. <TextField
  237. id={f.fieldName}
  238. variant="outlined"
  239. autoComplete="off"
  240. size={"small"}
  241. value={data != undefined ? data[f.fieldName] : ''}
  242. type="date"
  243. style={{ width: '100%' }}
  244. // onChange={handleDate}
  245. onChange={(e) => handleDate(e, f.fieldName)}
  246. />
  247. </Grid>
  248. </Grid>;
  249. }
  250. else if (f.type == 'photo') {
  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. <img src={imgPreview == null ? data['photo_url'] : imgPreview} style={{ width: '120px', height: '120px', border: '1px solid grey' }}></img>
  259. <input type='file' id='img-upload' onChange={(e) => handleImgUpload(e, f.fieldName)}></input>
  260. </Grid>
  261. </Grid>;
  262. }
  263. else if (f.type == 'dropdown') {
  264. if (f.fieldName == 'priority') {
  265. return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
  266. <Grid item xs={12} sm={5}>
  267. <Box style={{ width: '150px' }}>
  268. <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
  269. </Box>
  270. </Grid>
  271. <Grid item xs={12} sm={7}>
  272. <NativeSelect
  273. id="demo-customized-select-native"
  274. value={data != undefined ? data[f.fieldName] : ''}
  275. onChange={(e) => handleDropDownChange(e, f.fieldName)}
  276. id={f.fieldName}
  277. input={<BootstrapInput />}
  278. style={{ width: '100%' }}
  279. >
  280. <option aria-label="None" value="" >Select</option>
  281. {f.options.map((d, i) => {
  282. return <option name={d.name} value={d.id}>{d.name}</option>;
  283. })}
  284. </NativeSelect>
  285. </Grid>
  286. </Grid>;
  287. } else {
  288. var fn = f.fieldName.split('_');
  289. var fieldId = fn[0] + '_' + 'id';
  290. return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
  291. <Grid item xs={12} sm={5}>
  292. <Box style={{ width: '150px' }}>
  293. <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
  294. </Box>
  295. </Grid>
  296. <Grid item xs={12} sm={7}>
  297. <NativeSelect
  298. id="demo-customized-select-native"
  299. value={data != undefined ? data[fieldId] : ''}
  300. onChange={(e) => handleDropDownChange(e, f.fieldName)}
  301. id={f.fieldName}
  302. input={<BootstrapInput />}
  303. style={{ width: '100%' }}
  304. >
  305. <option aria-label="None" value="" >Select</option>
  306. {f.options.map((d, i) => {
  307. return <option name={d.name} value={d.id}>{d.name}</option>;
  308. })}
  309. </NativeSelect>
  310. </Grid>
  311. </Grid>;
  312. }
  313. }
  314. })}
  315. </Grid>
  316. {currentTabName == 'account' ?
  317. <Grid item xs={11}>
  318. <Box>
  319. <Button style={{ color: 'white', backgroundColor: buttonColor != undefined ? buttonColor : 'blue', float: 'right' }}
  320. onClick={handleInvite}
  321. > Invite</Button>
  322. </Box>
  323. </Grid>
  324. :
  325. <Grid item xs={11}>
  326. <Box>
  327. <Button style={{ color: 'white', backgroundColor: 'grey', float: 'right', marginLeft: '10px' }}
  328. onClick={handleCancel}
  329. ><CancelIcon /> Cancel</Button>
  330. </Box>
  331. {data.status == 'requested' ? <Box>
  332. <Button style={{ color: 'white', backgroundColor: buttonColor != undefined ? buttonColor : 'blue', float: 'right', marginLeft: '10px' }}
  333. onClick={() => handleApproved()}
  334. >Approved</Button>
  335. </Box> :
  336. <Box >
  337. <Button style={{ color: 'white', backgroundColor: buttonColor != undefined ? buttonColor : 'blue', float: 'right' }}
  338. onClick={handleSave}
  339. ><SaveIcon /> Save</Button>
  340. </Box>
  341. }
  342. </Grid>
  343. }
  344. </Grid>
  345. </div>
  346. );
  347. }
  348. FieldEditor.propTypes = {
  349. history: PropTypes.object,
  350. fields: PropTypes.array.isRequired,
  351. optionsData: PropTypes.array,
  352. isNew: PropTypes.bool.isRequired,
  353. onCreate: PropTypes.func.isRequired,
  354. onUpdate: PropTypes.func.isRequired,
  355. onCancel: PropTypes.func,
  356. onApproved: PropTypes.func,
  357. onInvite: PropTypes.func,
  358. data: PropTypes.object,
  359. currentTabName: PropTypes.string,
  360. buttonColor: PropTypes.any
  361. };
  362. export default (FieldEditor);