regform.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. import React, {useState} from "react";
  2. import axios from "axios";
  3. import DateFnsUtils from '@date-io/date-fns';
  4. import {nb} from 'date-fns/locale'
  5. import {DateTimePicker, MuiPickersUtilsProvider} from '@material-ui/pickers';
  6. import {makeStyles} from '@material-ui/core/styles';
  7. import ReCAPTCHA from "react-google-recaptcha";
  8. import {
  9. Button,
  10. ButtonGroup,
  11. Container,
  12. Checkbox,
  13. CssBaseline,
  14. Dialog,
  15. DialogTitle,
  16. DialogContent,
  17. DialogActions,
  18. FormControl,
  19. FormControlLabel,
  20. FormGroup,
  21. Grid,
  22. IconButton,
  23. Paper,
  24. TextField,
  25. Typography,
  26. } from '@material-ui/core';
  27. import {
  28. Add,
  29. Remove,
  30. } from '@material-ui/icons'
  31. const useStyles = makeStyles((theme) => ({
  32. fieldset: {
  33. //border: 'none',
  34. marginBottom: theme.spacing(3),
  35. paddingBottom: theme.spacing(3),
  36. },
  37. form: {
  38. width: '100%',
  39. marginTop: theme.spacing(1),
  40. flexGrow: 1,
  41. },
  42. paper: {
  43. padding: theme.spacing(2),
  44. alignItems: 'center',
  45. display: 'flex',
  46. flexDirection: 'column',
  47. }
  48. }));
  49. const SubmitButton = (props) => {
  50. const [isApproved, setIsApproved] = useState(false);
  51. const recaptchaRef = React.createRef();
  52. const onChange = (value) => {
  53. console.log("Captcha value:", value);
  54. setIsApproved(true);
  55. }
  56. return (
  57. <React.Fragment>
  58. <center>
  59. <ReCAPTCHA
  60. onChange={onChange}
  61. onExpired={() => isApproved ? setIsApproved(false) : false}
  62. ref={recaptchaRef}
  63. sitekey={"6LfRxgAVAAAAALlMOyD5h_a6gvWulxGqCC5gKJvd"}
  64. size={"invisible"}
  65. />
  66. </center>
  67. <Button
  68. color={"primary"}
  69. variant={"contained"}
  70. fullWidth
  71. type={"submit"}
  72. onClick={(e) => {
  73. recaptchaRef.current.execute();
  74. }}
  75. >Send skjema</Button>
  76. </React.Fragment>
  77. );
  78. }
  79. const RegForm = (props) => {
  80. const classes = useStyles();
  81. const [inputs, updateInputs] = useState({
  82. dates: [{date: new Date(), duration: 0}],
  83. });
  84. const inputHandler = (event) => {
  85. const target = event.target
  86. updateInputs((prevState) => ({...prevState, [target.id]: target.value}));
  87. };
  88. const inputCategoryHandler = (type, event, category) => {
  89. const keys = Object.keys(inputs).filter(idx => idx == type);
  90. let arr = keys.length == 0 ? [] : inputs[keys[0]];
  91. if (event.target.checked)
  92. arr.push(category);
  93. else
  94. arr = arr.filter(item => item.id != category.id);
  95. updateInputs((prevState) => ({...prevState, [type]: arr}));
  96. }
  97. const dateAddHandler = (idx) => {
  98. inputs.dates.splice(idx, 0, {...inputs.dates[idx]});
  99. updateInputs((prevState) => ({...prevState, dates: inputs.dates}));
  100. }
  101. const dateRemoveHandler = (idx) => {
  102. if (inputs.dates.length == 1)
  103. return;
  104. if (!inputs.dates[idx])
  105. return;
  106. updateInputs(prevState => ({...prevState, dates: [...inputs.dates.slice(0, idx), ...inputs.dates.slice(idx+1)]}));
  107. }
  108. const dateSaveHandler = (idx, e) => {
  109. if (!inputs.dates[idx])
  110. return;
  111. inputs.dates[idx].date = e;
  112. updateInputs((prevState) => ({...prevState, dates: inputs.dates}));
  113. }
  114. const dateDurationSaveHandler = (idx, e) => {
  115. if (!inputs.dates[idx])
  116. return;
  117. const target = e.target;
  118. inputs.dates[idx].duration = parseInt(target.value, 10);
  119. updateInputs((prevState) => ({...prevState, dates: inputs.dates}));
  120. }
  121. const submitHandler = (event) => {
  122. event.PreventDefault();
  123. console.log(event);
  124. }
  125. return (
  126. <Container component="main" maxWidth="md">
  127. <CssBaseline />
  128. <Paper className={classes.paper}>
  129. <form className={classes.form}>
  130. <FormControl component={"fieldset"} className={classes.fieldset}>
  131. <Typography component={"legend"} variant={"h5"}>
  132. Om arrangøren
  133. </Typography>
  134. <Grid container spacing={3}>
  135. <Grid item xs={12} sm={7} md={8}>
  136. <TextField
  137. id={"organizer"}
  138. label={"Navn på arrangør"}
  139. onChange={inputHandler}
  140. required
  141. fullWidth
  142. autoFocus
  143. />
  144. </Grid>
  145. <Grid item xs={12} sm={5} md={4}>
  146. <TextField
  147. id={"organization_number"}
  148. label={"Org.nummer"}
  149. onChange={inputHandler}
  150. required
  151. fullWidth
  152. />
  153. </Grid>
  154. <Grid item xs={12} sm={6}>
  155. <TextField
  156. id={"contact_name"}
  157. label={"Kontakt person"}
  158. onChange={inputHandler}
  159. required
  160. fullWidth
  161. />
  162. </Grid>
  163. <Grid item xs={12} sm={6}>
  164. <TextField
  165. id={"contact_email"}
  166. label={"Epostadresse"}
  167. onChange={inputHandler}
  168. type={"email"}
  169. required
  170. fullWidth
  171. />
  172. </Grid>
  173. <Grid item xs={12} sm={6}>
  174. <TextField
  175. id={"contact_phone"}
  176. label={"Telefonnummer"}
  177. onChange={inputHandler}
  178. type={"tel"}
  179. required
  180. fullWidth
  181. />
  182. </Grid>
  183. <Grid item xs={12} sm={6}>
  184. <TextField
  185. id={"contact_homepage"}
  186. label={"Hjemmesideadresse"}
  187. placeholder={"https:// ...."}
  188. required
  189. fullWidth
  190. />
  191. </Grid>
  192. </Grid>
  193. </FormControl>
  194. <FormControl component={"fieldset"} className={classes.fieldset}>
  195. <Typography component={"legend"} variant={"h5"}>
  196. Om arrangementet
  197. </Typography>
  198. <Grid container spacing={3}>
  199. <Grid item xs={12}>
  200. <TextField
  201. id={"event_name"}
  202. label={"Navn på arrangement"}
  203. onChange={inputHandler}
  204. required
  205. fullWidth
  206. />
  207. </Grid>
  208. {inputs.dates.map((date, idx) => (
  209. <React.Fragment key={idx}>
  210. <Grid item xs={6}>
  211. <MuiPickersUtilsProvider utils={DateFnsUtils} locale={nb}>
  212. <DateTimePicker
  213. fullWidth
  214. format={"do MMMM y HH:mm (h:mm a)"}
  215. ampm={false}
  216. value={date.date}
  217. onChange={e => dateSaveHandler(idx, e)}
  218. margin={"normal"}
  219. />
  220. </MuiPickersUtilsProvider>
  221. </Grid>
  222. <Grid item xs={4}>
  223. <TextField
  224. id={"event_duration"}
  225. label={"Varighet (timer)"}
  226. onChange={e => dateDurationSaveHandler(idx, e)}
  227. type={"number"}
  228. placeholder={"antall timer"}
  229. value={date.duration}
  230. fullWidth
  231. />
  232. </Grid>
  233. <Grid item xs={1}>
  234. <IconButton onClick={() => dateAddHandler(idx)}><Add /></IconButton>
  235. </Grid>
  236. <Grid item xs={1}>
  237. <IconButton onClick={() => dateRemoveHandler(idx)}><Remove /></IconButton>
  238. </Grid>
  239. </React.Fragment>
  240. ))}
  241. <Grid item xs={12} sm={8}>
  242. <TextField
  243. id={'event_location'}
  244. label={"Sted"}
  245. onChange={inputHandler}
  246. placeholder={"Hvor skjer arrangementet?"}
  247. fullWidth
  248. required
  249. />
  250. </Grid>
  251. <Grid item xs={12} sm={4}>
  252. <TextField
  253. id={"event_capacity"}
  254. label={"Kapasitet"}
  255. placeholder={"Antall personer"}
  256. onChange={inputHandler}
  257. type={"number"}
  258. required
  259. fullWidth
  260. />
  261. </Grid>
  262. <Grid item xs={12}>
  263. <TextField
  264. id={"event_description"}
  265. label={"Beskrivelse av arrangement"}
  266. onChange={inputHandler}
  267. placeholder={"Forklar detaljert om ditt arrangement - dette skal besøkende lese!"}
  268. multiline
  269. fullWidth
  270. required
  271. />
  272. </Grid>
  273. <Grid item xs={12} sm={6}>
  274. <TextField
  275. id="event_photo"
  276. label={"Photo-link til arrangement"}
  277. onChange={inputHandler}
  278. placeholder={"Kan for eks. være en bilde-fil eller mappe med bilder i Dropbox."}
  279. fullWidth
  280. required
  281. />
  282. </Grid>
  283. <Grid item xs={12} sm={6}>
  284. <TextField
  285. id="event_booking"
  286. label={"Link til booking"}
  287. onChange={inputHandler}
  288. placeholder={"https:// ..."}
  289. fullWidth
  290. required
  291. />
  292. </Grid>
  293. <Grid item xs={12} sm={6}>
  294. <CategorySelection
  295. cid={"5ed0f77a42f75848a95ebf03"}
  296. category="Kategorier"
  297. name="categories"
  298. selected={inputs.categories || []}
  299. inputCategoryHandler={inputCategoryHandler}
  300. />
  301. </Grid>
  302. <Grid item xs={12} sm={6}>
  303. <CategorySelection
  304. cid={"5ed10cffd2b21cfb3b269088"}
  305. category="Målgrupper"
  306. name="audiences"
  307. selected={inputs.audiences || []}
  308. inputCategoryHandler={inputCategoryHandler}
  309. />
  310. </Grid>
  311. </Grid>
  312. </FormControl>
  313. <Grid container justify={"center"}>
  314. <Grid item xs={8}>
  315. <SubmitButton text={"Send skjema"}/>
  316. </Grid>
  317. </Grid>
  318. </form>
  319. </Paper>
  320. </Container>
  321. )
  322. }
  323. const CategorySelection = (props) => {
  324. const [error, setError] = useState(null);
  325. const [isLoading, setIsLoading] = useState(true);
  326. const [availableItems, setAvailableItems] = useState([]);
  327. React.useEffect(() => {
  328. axios.get("https://magy.giaever.online/tff/api/webflow_items?cid=" + props.cid)
  329. .then((response) => {
  330. const data = response.data['hydra:member'];
  331. setAvailableItems(response.data['hydra:member']);
  332. })
  333. .catch((error) => {
  334. setError(error);
  335. })
  336. .then(() => {
  337. setIsLoading(false);
  338. });
  339. }, []);
  340. return (
  341. <React.Fragment>
  342. <DialogCancelOk
  343. buttonDesc={isLoading ? `Laster ${props.category}` : `Velg ${props.category}`}
  344. buttonDisabled={isLoading}
  345. dialogTitle={`Velg ${props.category}`}
  346. >
  347. {isLoading ?
  348. <p>
  349. Laster...
  350. </p>
  351. :
  352. <FormGroup>
  353. {availableItems.map(item => <FormControlLabel
  354. key={item.id}
  355. control={
  356. <Checkbox
  357. checked={props.selected.filter(sitem => sitem.id == item.id).length > 0}
  358. value={item.id}
  359. onChange={() => props.inputCategoryHandler(props.name, event, item)}
  360. />
  361. }
  362. label={item.name}
  363. />
  364. )}
  365. </FormGroup>
  366. }
  367. </DialogCancelOk>
  368. <ul>{props.selected.map(item => <li key={item.id}>{item.name}</li>)}</ul>
  369. </React.Fragment>
  370. )
  371. }
  372. const DialogCancelOk = (props) => {
  373. const [open, setOpen] = useState(false);
  374. const handleClickOpen = () => {
  375. setOpen(true);
  376. };
  377. const handleClickClose = () => {
  378. setOpen(false);
  379. };
  380. return (
  381. <div>
  382. <Button
  383. fullWidth
  384. disabled={props.buttonDisabled}
  385. color={"secondary"}
  386. variant={props.buttonDisabled ? "outlined" : "contained"}
  387. onClick={handleClickOpen}>
  388. {props.buttonDesc}
  389. </Button>
  390. <Dialog
  391. disableBackdropClick
  392. disableEscapeKeyDown
  393. open={open}
  394. onClose={handleClickClose}
  395. >
  396. <DialogTitle>{props.dialogTitle}</DialogTitle>
  397. <DialogContent>
  398. {props.children}
  399. </DialogContent>
  400. <DialogActions>
  401. <Button onClick={handleClickClose} color={"primary"}>
  402. Ferdig
  403. </Button>
  404. </DialogActions>
  405. </Dialog>
  406. </div>
  407. )
  408. }
  409. export default RegForm;