calendar.view.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. import React, { Component } from "react";
  2. import ContentWrapper from "@/components/Layout/ContentWrapper";
  3. import { Card, CardBody, CardHeader, CardTitle, Button, Row, Col, FormGroup, Input } from "reactstrap";
  4. import { getPelaporan, getOneLaporan, updateLaporan } from "@/actions/pelaporan";
  5. import { updateJadwal } from "@/actions/penjadwalan";
  6. import DetailLaporan from "@/components/Penjadwalan/DetailLaporan";
  7. import Link from "next/link";
  8. import FullCalendar from "@fullcalendar/react";
  9. import dayGridPlugin from "@fullcalendar/daygrid";
  10. import timeGridPlugin from "@fullcalendar/timegrid";
  11. import interactionPlugin, { Draggable } from "@fullcalendar/interaction";
  12. import listPlugin from "@fullcalendar/list";
  13. import bootstrapPlugin from "@fullcalendar/bootstrap";
  14. import Select from "react-select";
  15. import moment from "moment-timezone";
  16. import { connect } from "react-redux";
  17. import Loader from "@/components/Common/Loader";
  18. import Router from "next/router";
  19. import { ToastContainer, toast } from "react-toastify";
  20. import { Formik, Form, Field, ErrorMessage } from "formik";
  21. import * as Yup from "yup";
  22. import Datetime from "react-datetime";
  23. import 'moment/locale/id';
  24. import { getCsrf } from "../../actions/security";
  25. import { createLog } from "../../actions/log";
  26. moment.locale('id')
  27. import Swal from "sweetalert2";
  28. const checkIfFilesAreTooBig = (files) => {
  29. let valid = true;
  30. if (files) {
  31. files.map((file) => {
  32. if (file.size > 15 * 1024 * 1024) {
  33. valid = false;
  34. }
  35. });
  36. }
  37. return valid;
  38. };
  39. const status = [
  40. { value: "Ditindaklanjuti DIKTI", label: "Ditindaklanjuti DIKTI", className: "State-ACT" },
  41. { value: "Delegasi ke LLDIKTI", label: "Delegasi ke LLDIKTI", className: "State-ACT" },
  42. { value: "Ditutup", label: "Ditutup", className: "State-ACT" },
  43. ];
  44. const statusLLDIKTI = [
  45. { value: "Ditindaklanjuti LLDIKTI", label: "Ditindaklanjuti LLDIKTI", className: "State-ACT" },
  46. { value: "Delegasi ke DIKTI", label: "Delegasi ke DIKTI", className: "State-ACT" },
  47. { value: "Ditutup", label: "Ditutup", className: "State-ACT" },
  48. ];
  49. const jadwalSchema = Yup.object().shape({
  50. judul: Yup.string().required("Wajib diisi"),
  51. dari_tanggal: Yup.date().required("Wajib diisi"),
  52. sampai_tanggal: Yup.date().required("Wajib diisi"),
  53. });
  54. const laporanSchema = Yup.object().shape({
  55. keterangan: Yup.string().required("Harus diisi"),
  56. dokumen: Yup.array().min(1).test("filesize", "Maksimal ukuran dokumen 15mb", checkIfFilesAreTooBig),
  57. });
  58. const ditutupSchema = Yup.object().shape({
  59. keterangan: Yup.string().required("Harus diisi"),
  60. dokumen: Yup.array().min(1).required("Wajib diisi").test("filesize", "Maksimal ukuran dokumen 15mb", checkIfFilesAreTooBig),
  61. });
  62. let Dropzone = null;
  63. class DropzoneWrapper extends Component {
  64. state = {
  65. isClient: false,
  66. };
  67. componentDidMount = () => {
  68. Dropzone = require("react-dropzone").default;
  69. this.setState({ isClient: true });
  70. };
  71. render() {
  72. return Dropzone ? <Dropzone {...this.props}>{this.props.children}</Dropzone> : null;
  73. }
  74. }
  75. class Calendar extends Component {
  76. calendarPlugins = [interactionPlugin, dayGridPlugin, timeGridPlugin, listPlugin, bootstrapPlugin];
  77. calendarHeader = {
  78. left: "prev,next today",
  79. center: "title",
  80. right: "dayGridMonth,timeGridWeek,timeGridDay",
  81. };
  82. constructor(props) {
  83. super(props);
  84. this.state = {
  85. selectedEvent: null,
  86. evRemoveOnDrop: true,
  87. evNewName: "",
  88. externalEvents: [],
  89. dataLaporan: [],
  90. dataEvent: [],
  91. laporan: {},
  92. selectedOption: null,
  93. color: "",
  94. disabled: true,
  95. files: [],
  96. };
  97. }
  98. onDrop = (selectedFile) => {
  99. this.setState({
  100. selectedFile: selectedFile.map((file) =>
  101. Object.assign(file, {
  102. preview: URL.createObjectURL(file),
  103. })
  104. ),
  105. stat: "Added " + selectedFile.length + " file(s)",
  106. });
  107. const selectFile = this.state.selectedFile
  108. this.setState(prevState => ({
  109. files: [...prevState.files, ...selectFile]
  110. }))
  111. };
  112. uploadFiles = (e) => {
  113. e.preventDefault();
  114. e.stopPropagation();
  115. this.setState({
  116. stat: this.state.files.length ? "Dropzone ready to upload " + this.state.files.length + " file(s)" : "No files added.",
  117. });
  118. };
  119. clearFiles = (e) => {
  120. e.preventDefault();
  121. e.stopPropagation();
  122. this.setState({
  123. stat: this.state.files.length ? this.state.files.length + " file(s) cleared." : "No files to clear.",
  124. });
  125. this.setState({
  126. files: [],
  127. });
  128. };
  129. static getInitialProps = ({ query }) => ({ query });
  130. async componentDidMount() {
  131. const { token, query } = this.props;
  132. const laporan = await getOneLaporan(token, query.id);
  133. const dataLaporan = await getPelaporan(token, { jadwal: true });
  134. this.setState({ dataLaporan });
  135. this.getDataEvent();
  136. this.defaultStatus();
  137. this.setState({ laporan });
  138. let color = "#" + Math.random().toString(16).slice(2, 8);
  139. if (laporan.data.jadwal) {
  140. color = laporan.data.jadwal.warna;
  141. }
  142. this.setState({ color });
  143. }
  144. componentShouldUpdate(nextProps, nextState) {
  145. return nextState.dataLaporan !== this.state.dataLaporan;
  146. }
  147. getStatus = () => (this.props.user?.role.id === 2021 ? statusLLDIKTI : status);
  148. getDataEvent = () => {
  149. const dataEvent = this.state.dataLaporan.data.map((e) => ({
  150. id: e._id,
  151. title: e.jadwal.judul,
  152. start: moment(e.jadwal.dari_tanggal).format("YYYY-MM-DD"),
  153. end: moment(e.jadwal.sampai_tanggal).add(1, "d").format("YYYY-MM-DD"),
  154. backgroundColor: e.jadwal.warna,
  155. borderColor: e.jadwal.warna,
  156. }));
  157. this.setState({ dataEvent });
  158. };
  159. eventClick = (info) => {
  160. const data = {
  161. title: info.event.title,
  162. start: moment(info.event.start).format("DD MMMM YYYY"),
  163. end: moment(info.event.end - 1).format("DD MMMM YYYY"),
  164. };
  165. this.setState({ selectedEvent: data });
  166. };
  167. handleEventReceive = (info) => {
  168. var styles = getComputedStyle(info.draggedEl);
  169. info.event.setProp("backgroundColor", styles.backgroundColor);
  170. info.event.setProp("borderColor", styles.borderColor);
  171. this.handleEventCalendar(info);
  172. };
  173. logSuccessUpdateJadwal = async () => {
  174. const { query, token } = this.props;
  175. const { id } = query;
  176. const getToken = await getCsrf();
  177. const _csrf = getToken.token;
  178. await createLog(token, { aktivitas: `Berhasil menetapkan jadwal, id: ${id}`,menu: "Penjadwalan", _csrf: _csrf });
  179. }
  180. handleEventCalendar = async (data) => {
  181. if (this.props.user.role.id === 2024) {
  182. Swal.fire({
  183. icon: 'error',
  184. title: 'Oops...',
  185. html: 'Maaf anda tidak memiliki akses untuk menyelesaikan<p> proses ini.</p>',
  186. confirmButtonColor: "#3e3a8e",
  187. confirmButtonText: 'Oke'
  188. })
  189. } else {
  190. const { query, token } = this.props;
  191. const { id } = query;
  192. const { color, laporan } = this.state;
  193. const getToken = await getCsrf();
  194. const _csrf = getToken.token;
  195. await toast.promise(
  196. updateJadwal(token, id, {
  197. judul: "No.Laporan " + laporan.data.no_laporan + " - " + data.judul,
  198. dari_tanggal: data.dari_tanggal,
  199. sampai_tanggal: data.sampai_tanggal,
  200. warna: color,
  201. }, _csrf),
  202. {
  203. pending: "Loading",
  204. success: "Success",
  205. error: "Error",
  206. }
  207. );
  208. Router.push("/app/penjadwalan");
  209. const dataLaporan = await getPelaporan(token, { jadwal: true });
  210. this.setState({ dataLaporan });
  211. this.getDataEvent();
  212. }
  213. };
  214. defaultStatus = async () => {
  215. const status = this.getStatus();
  216. return this.setState({ selectedOption: status[0] });
  217. };
  218. handleChangeSelect = (selectedOption) => this.setState({ selectedOption });
  219. logUpdateLaporanError = async () => {
  220. const getToken = await getCsrf();
  221. const _csrf = getToken.token;
  222. const { token, query } = this.props;
  223. const { id } = query;
  224. await createLog(token, { aktivitas: `Berhasil mengubah data laporan, id: ${id}`, _csrf: _csrf, menu: "Penjadwalan" });
  225. }
  226. logdelegasi = async () => {
  227. const getToken = await getCsrf();
  228. const _csrf = getToken.token;
  229. const { token, query } = this.props;
  230. const { id } = query;
  231. await createLog(token, { aktivitas: `Berhasil Delegasi Laporan, id: ${id}`, _csrf: _csrf , menu :"Penjadwalan"});
  232. }
  233. logDitutup = async () => {
  234. const getToken = await getCsrf();
  235. const _csrf = getToken.token;
  236. const { token, query } = this.props;
  237. const { id } = query;
  238. await createLog(token, { aktivitas: `Berhasil menutup laporan, id: ${id}`, _csrf: _csrf, menu: "Penjadwalan" });
  239. }
  240. handleSimpan = async (value) => {
  241. if (this.props.user.role.id === 2024) {
  242. Swal.fire({
  243. icon: 'error',
  244. title: 'Oops...',
  245. html: 'Maaf anda tidak memiliki akses untuk menyelesaikan<p> proses ini.</p>',
  246. confirmButtonColor: "#3e3a8e",
  247. confirmButtonText: 'Oke'
  248. })
  249. } else {
  250. const getToken = await getCsrf();
  251. const _csrf = getToken.token;
  252. const { token, query } = this.props;
  253. const { id } = query;
  254. let update = null;
  255. if (value.status.value === this.getStatus()[1].value || value.status.value === this.getStatus()[2].value) {
  256. const toastid = toast.loading("Please wait...");
  257. const data = { keterangan: value.keterangan };
  258. const formdata = new FormData();
  259. formdata.append("keterangan", value.keterangan);
  260. this.state.files.forEach((e) => {
  261. formdata.append("dokumen", e);
  262. });
  263. formdata.append("aktif", "false");
  264. if (value.status.value === this.getStatus()[1].value) {
  265. data.change_role = "true";
  266. update = await updateLaporan(token, id, data, _csrf);
  267. await this.logdelegasi()
  268. Router.push("/app/penjadwalan");
  269. } else if (value.status.value === this.getStatus()[2].value) {
  270. update = await updateLaporan(token, id, formdata, _csrf + `&redudansi=true`);
  271. await this.logDitutup()
  272. Router.push("/app/penjadwalan");
  273. }
  274. if (!update) {
  275. toast.update(toastid, { render: "Error", type: "error", isLoading: false, autoClose: true, closeButton: true });
  276. this.logUpdateLaporanError()
  277. } else {
  278. toast.update(toastid, { render: "Success", type: "success", isLoading: false, autoClose: true, closeButton: true });
  279. this.logUpdateLaporanSuccess()
  280. Router.push("/app/penjadwalan");
  281. }
  282. Router.push("/app/penjadwalan");
  283. }
  284. Router.push("/app/penjadwalan");
  285. }
  286. };
  287. render() {
  288. const { files, externalEvents, laporan, selectedOption, selectedEvent } = this.state;
  289. const removeFile = file => () => {
  290. const newFiles = [...files]
  291. newFiles.splice(newFiles.indexOf(file), 1)
  292. this.setState({
  293. files: newFiles,
  294. });
  295. }
  296. const thumbs = files.map((file, index) => (
  297. <p>
  298. <em className="far fa-file" />&nbsp;&nbsp;{file.name}
  299. <button className="bg-transparent button-transparent border-0 fas fa-trash text-danger float-right" onClick={removeFile(file)} />
  300. </p>
  301. ));
  302. return (
  303. <ContentWrapper>
  304. <div className="content-heading">
  305. <span className="font-color-white">
  306. Membuat Jadwal Pemeriksaan
  307. </span>
  308. <div className="ml-auto">
  309. <Link href="/app/penjadwalan">
  310. <Button className="color-3e3a8e" color>
  311. <span className="font-color-white">
  312. &lt; Kembali
  313. </span>
  314. </Button>
  315. </Link>
  316. </div>
  317. </div>
  318. <div className="calendar-app">
  319. {laporan.data ? (
  320. <Row>
  321. <Col>
  322. <Card className="card-default">
  323. <CardBody>
  324. <DetailLaporan noStatus data={laporan.data} role={this.props.user.role.id} />
  325. </CardBody>
  326. </Card>
  327. </Col>
  328. </Row>
  329. ) : (
  330. <Row className="mb-4">
  331. <Col>
  332. <Loader />
  333. </Col>
  334. </Row>
  335. )}
  336. <div className="row">
  337. <div className="col-xl-4 col-lg-5">
  338. <div className="row">
  339. <div className="col-lg-12 col-md-6 col-12">
  340. <Card className="card-default">
  341. <div class="header-penjadwalan">
  342. <h2 class="card-title-1">Status Pelaporan</h2>
  343. </div>
  344. <CardBody>
  345. <Formik
  346. enableReinitialize={true}
  347. initialValues={{
  348. status: this.getStatus()[0],
  349. keterangan: "",
  350. }}
  351. validationSchema={selectedOption?.value === this.getStatus()[2].value || selectedOption?.value === this.getStatus()[1].value ? laporanSchema : null}
  352. onSubmit={this.handleSimpan}
  353. >
  354. {({ isSubmitting }) => (
  355. <Form>
  356. <FormGroup>
  357. <label className="col-form-label">Status Laporan</label>
  358. <Field name="status">
  359. {({ field, form }) => (
  360. <Select
  361. value={field.value}
  362. onChange={(e) => {
  363. form.setFieldValue(field.name, e);
  364. this.handleChangeSelect(e);
  365. }}
  366. options={this.getStatus()}
  367. required
  368. isDisabled={laporan.data?.sanksi}
  369. />
  370. )}
  371. </Field>
  372. <ErrorMessage name="status" component="div" className="form-text text-danger" />
  373. </FormGroup>
  374. {selectedOption?.value === this.getStatus()[0].value ? (
  375. ""
  376. ) : (
  377. selectedOption?.value === this.getStatus()[1].value ? (
  378. <FormGroup>
  379. <label className="col-form-label">Keterangan<span className=" text-danger">*</span></label>
  380. <Field name="keterangan">{({ field, form }) => <Input type="text" placeholder="Keterangan" {...field} />}</Field>
  381. <ErrorMessage name="keterangan" component="div" className="form-text text-danger" />
  382. </FormGroup>
  383. ) : (
  384. <div>
  385. <FormGroup >
  386. <label className="col-form-label">Keterangan<span className=" text-danger">*</span></label>
  387. <Field name="keterangan">{({ field, form }) => <Input type="text" placeholder="Keterangan" {...field} />}</Field>
  388. <ErrorMessage name="keterangan" component="div" className="form-text text-danger" />
  389. </FormGroup>
  390. <FormGroup >
  391. <label className=" col-form-label">Upload File Pendukung<span className="text-danger">*</span></label>
  392. <div >
  393. <Field name="dokumen">
  394. {({ field, form, meta }) => (
  395. <DropzoneWrapper
  396. className=""
  397. onDrop={(e) => {
  398. this.onDrop(e);
  399. form.setFieldValue(field.name, e);
  400. }}
  401. >
  402. {({ getRootProps, getInputProps, isDragActive }) => {
  403. return (
  404. <div {...getRootProps()} className={"dropzone card" + (isDragActive ? "dropzone-drag-active" : "")}>
  405. <input name="dokumen" {...getInputProps()} />
  406. <div className="dropzone-style-1">
  407. <div className="center-ver-hor dropzone-previews flex">{this.state.files.length > 0 ?
  408. <div className="text-center fa-2x icon-cloud-upload mr-2 ">
  409. <h5 className="text-center dz-default dz-message">Klik untuk tambah file</h5>
  410. </div> :
  411. <div className="text-center fa-2x icon-cloud-upload mr-2 ">
  412. <h5 className="text-center dz-default dz-message">Klik untuk upload dokumen</h5>
  413. </div>
  414. }
  415. </div>
  416. </div>
  417. <div className="d-flex align-items-center">
  418. <small className="ml-auto">
  419. <button
  420. type="button"
  421. className="btn btn-link"
  422. onClick={(e) => {
  423. this.clearFiles(e);
  424. form.setFieldValue(field.name, []);
  425. }}
  426. >
  427. Reset dokumen
  428. </button>
  429. </small>
  430. </div>
  431. </div>
  432. );
  433. }}
  434. </DropzoneWrapper>
  435. )}
  436. </Field>
  437. {thumbs}
  438. <ErrorMessage name="dokumen" component="div" className="form-text text-danger" />
  439. <p className="mrgn-top-5 font-color-black">
  440. Ukuran setiap dokumen maksimal 15mb
  441. </p>
  442. </div>
  443. </FormGroup>
  444. </div>
  445. )
  446. )}
  447. <div className="btn-simpanjadwal">
  448. <Button className="text-btn-penjadwalan-1 btn-colorpenjadwalan color-3e3a8e" color block disabled={laporan.data?.sanksi || isSubmitting} >
  449. <h4 className="text-btn-penjadwalan-1 font-color-white">Simpan</h4>
  450. </Button>
  451. </div>
  452. </Form>
  453. )}
  454. </Formik>
  455. </CardBody>
  456. </Card>
  457. {selectedOption?.value === this.getStatus()[2].value || selectedOption?.value === this.getStatus()[1].value ? (
  458. ""
  459. ) : (
  460. <>
  461. <Card className="card-default" title="">
  462. <div class="header-penjadwalan">
  463. <h2 className="card-title-1">Input Jadwal</h2>
  464. </div>
  465. <CardBody>
  466. <Formik
  467. enableReinitialize={true}
  468. initialValues={{
  469. judul: laporan.data?.jadwal?.judul ? laporan.data.jadwal.judul.split("- ")[1] : "",
  470. dari_tanggal: laporan.data?.jadwal?.dari_tanggal ? moment(laporan.data.jadwal.dari_tanggal).format("DD MMMM YYYY") : "",
  471. sampai_tanggal: laporan.data?.jadwal?.sampai_tanggal ? moment(laporan.data.jadwal.sampai_tanggal).format("DD MMMM YYYY") : "",
  472. }}
  473. validationSchema={jadwalSchema}
  474. onSubmit={this.handleEventCalendar}
  475. >
  476. {({ isSubmitting }) => (
  477. <Form>
  478. <FormGroup>
  479. <label className="col-form-label">Warna</label>
  480. <div className="badge d-block" style={{ backgroundColor: this.state.color, color: "white" }}>
  481. {this.state.color}
  482. </div>
  483. {/* <div className="warna-penjadwalan-block" style={{ backgroundColor: this.state.color, color: "white" }}></div> */}
  484. </FormGroup>
  485. <FormGroup>
  486. <label className="col-form-label">Judul<span className=" text-danger">*</span></label>
  487. <Field name="judul">{({ field, form }) => <Input disabled={laporan.data?.sanksi} type="text" placeholder="judul" {...field} />}</Field>
  488. <ErrorMessage name="judul" component="div" className="form-text text-danger" />
  489. </FormGroup>
  490. <Row>
  491. <Col>
  492. <FormGroup>
  493. <label className="col-form-label">Dari Tanggal</label>
  494. <Field name="dari_tanggal">
  495. {({ field, form }) => (
  496. <Datetime
  497. timeFormat={false}
  498. locale="id"
  499. inputProps={{ className: "form-control" }}
  500. value={field.value}
  501. dateFormat="DD MMMM YYYY"
  502. closeOnSelect={true}
  503. onChange={(e) => {
  504. form.setFieldValue(field.name, e);
  505. }}
  506. />
  507. )}
  508. </Field>
  509. <ErrorMessage name="dari_tanggal" component="div" className="form-text text-danger" />
  510. </FormGroup>
  511. </Col>
  512. <Col>
  513. <FormGroup>
  514. <label className="col-form-label">Sampai Tanggal</label>
  515. <Field name="sampai_tanggal">
  516. {({ field, form }) => (
  517. <Datetime
  518. timeFormat={false}
  519. locale="id"
  520. dateFormat="DD MMMM YYYY"
  521. inputProps={{ className: "form-control" }}
  522. value={field.value}
  523. closeOnSelect={true}
  524. onChange={(e) => {
  525. form.setFieldValue(field.name, e);
  526. }}
  527. />
  528. )}
  529. </Field>
  530. <ErrorMessage name="sampai_tanggal" component="div" className="form-text text-danger" />
  531. </FormGroup>
  532. </Col>
  533. </Row>
  534. <FormGroup>
  535. <div className="btn-simpanpenjadwalan">
  536. <Button className="btn-colorpenjadwalan" color block type="submit" disabled={laporan.data?.sanksi || isSubmitting}>
  537. <h4 className="text-btn-penjadwalan-1 font-color-white">Simpan</h4>
  538. </Button>
  539. </div>
  540. </FormGroup>
  541. </Form>
  542. )}
  543. </Formik>
  544. </CardBody>
  545. </Card>
  546. </>
  547. )}
  548. <div className="mb-3">
  549. {selectedEvent && (
  550. <div>
  551. <p>Selected:</p>
  552. <div className="box-placeholder">{JSON.stringify(selectedEvent)}</div>
  553. </div>
  554. )}
  555. {!selectedEvent && (
  556. <div>
  557. <p>Click calendar to show information</p>
  558. </div>
  559. )}
  560. </div>
  561. </div>
  562. </div>
  563. </div>
  564. <div className="col-xl-8 col-lg-7">
  565. <Card className="card-default">
  566. <CardBody>
  567. {/* START calendar */}
  568. <FullCalendar
  569. defaultView={this.dayGridMonth}
  570. plugins={this.calendarPlugins}
  571. events={this.state.dataEvent}
  572. themeSystem={"bootstrap"}
  573. header={this.calendarHeader}
  574. deepChangeDetection={true}
  575. eventClick={this.eventClick}
  576. ></FullCalendar>
  577. </CardBody>
  578. </Card>
  579. </div>
  580. </div>
  581. </div>
  582. </ContentWrapper >
  583. );
  584. }
  585. }
  586. const mapStateToProps = (state) => ({ user: state.user, token: state.token });
  587. export default connect(mapStateToProps)(Calendar);