Browse Source

rev 11-07, issue 2,7

andi 3 years ago
parent
commit
06d8233478
4 changed files with 790 additions and 551 deletions
  1. 3 2
      components/Layout/Header.js
  2. 163 117
      components/Main/Login.js
  3. 1 1
      pages/app/pelaporan/index.js
  4. 623 431
      pages/laporan/new/index.js

+ 3 - 2
components/Layout/Header.js

@@ -4,7 +4,7 @@ import PropTypes from "prop-types";
 import Link from "next/link";
 import { UncontrolledDropdown, DropdownToggle, DropdownMenu, DropdownItem, ListGroup, ListGroupItem } from "reactstrap";
 import { logout } from "@/actions/auth";
-
+import { createLog } from "../../actions/log";
 import { connect } from "react-redux";
 import { bindActionCreators } from "redux";
 import * as actions from "../../store/actions/actions";
@@ -58,6 +58,7 @@ class Header extends Component {
 	handleLogout = async (e) => {
 		e.preventDefault();
 		// await logout();
+		await createLog(this.props.token, { aktivitas: "Berhasil Logout" });
 		this.props.tokenNull();
 		this.props.userNull();
 		// if (cek.success) {
@@ -224,7 +225,7 @@ Header.propTypes = {
 	settings: PropTypes.object,
 };
 
-const mapStateToProps = (state) => ({ settings: state.settings });
+const mapStateToProps = (state) => ({ settings: state.settings, token: state.token });
 const mapDispatchToProps = (dispatch) => ({
 	actions: bindActionCreators(actions, dispatch),
 	tokenNull: () => dispatch({ type: "SET_TOKEN", payload: null }),

+ 163 - 117
components/Main/Login.js

@@ -4,142 +4,188 @@ import Router from "next/router";
 import FormValidator from "@/components/Forms/Validator.js";
 import { connect } from "react-redux";
 import { login, getUser } from "@/actions/auth";
+import { createLog } from "@/actions/log";
 import axiosAPI from "@/config/axios";
 import { getPT } from "@/actions/PT";
 
 class Login extends Component {
-	constructor(props) {
-		super(props);
-		this.state = {
-			/* Group each form state in an object.
+  constructor(props) {
+    super(props);
+    this.state = {
+      /* Group each form state in an object.
 		   Property name MUST match the form name */
-			error: null,
-			formLogin: {
-				username: "",
-				password: "",
-			},
-		};
-	}
+      error: null,
+      formLogin: {
+        username: "",
+        password: "",
+      },
+      loading: false,
+    };
+  }
 
-	/**
-	 * Validate input using onChange event
-	 * @param  {String} formName The name of the form in the state object
-	 * @return {Function} a function used for the event
-	 */
-	validateOnChange = (event) => {
-		const input = event.target;
-		const form = input.form;
-		const value = input.type === "checkbox" ? input.checked : input.value;
+  /**
+   * Validate input using onChange event
+   * @param  {String} formName The name of the form in the state object
+   * @return {Function} a function used for the event
+   */
+  validateOnChange = (event) => {
+    const input = event.target;
+    const form = input.form;
+    const value = input.type === "checkbox" ? input.checked : input.value;
 
-		const result = FormValidator.validate(input);
+    const result = FormValidator.validate(input);
 
-		this.setState({
-			[form.name]: {
-				...this.state[form.name],
-				[input.name]: value,
-				errors: {
-					...this.state[form.name].errors,
-					[input.name]: result,
-				},
-			},
-		});
-	};
+    this.setState({
+      [form.name]: {
+        ...this.state[form.name],
+        [input.name]: value,
+        errors: {
+          ...this.state[form.name].errors,
+          [input.name]: result,
+        },
+      },
+    });
+  };
 
-	onSubmit = async (e) => {
-		try {
-			const form = e.target;
-			const inputs = [...form.elements].filter((i) => ["INPUT", "SELECT"].includes(i.nodeName));
+  onSubmit = async (e) => {
+    try {
+      const form = e.target;
+      const inputs = [...form.elements].filter((i) =>
+        ["INPUT", "SELECT"].includes(i.nodeName)
+      );
 
-			const { errors, hasError } = FormValidator.bulkValidate(inputs);
+      const { errors, hasError } = FormValidator.bulkValidate(inputs);
 
-			this.setState({
-				[form.name]: {
-					...this.state[form.name],
-					errors,
-				},
-			});
+      this.setState({
+        [form.name]: {
+          ...this.state[form.name],
+          errors,
+        },
+      });
 
-			console.log(hasError ? "Form has errors. Check!" : "Form Submitted!");
-			e.preventDefault();
-			if (!hasError) {
-				const { username, password } = this.state.formLogin;
-				const auth = await login(username, password);
-				this.props.setToken(auth.data.token);
-				this.props.setUser(auth.data.user);
-				axiosAPI.defaults.headers.common["Authorization"] = auth.data.token;
-				if (auth.data.user.role.id === 2022) {
-					Router.push({ pathname: "/pt/pemantauan" });
-				} else if ([2020, 2021, 2023].includes(auth.data.user.role.id)) {
-					Router.push({ pathname: "/app/pemantauan" });
-				} else {
-					this.setState({ error: "Akun tidak ada" });
-				}
-			}
-		} catch (error) {
-			this.setState({ error: error.response?.data.message || error.response });
-		}
-	};
+      console.log(hasError ? "Form has errors. Check!" : "Form Submitted!");
+      e.preventDefault();
+      if (!hasError) {
+        this.setState({ loading: true });
+        const { username, password } = this.state.formLogin;
+        const auth = await login(username, password);
+        this.props.setToken(auth.data.token);
+        this.props.setUser(auth.data.user);
+        axiosAPI.defaults.headers.common["Authorization"] = auth.data.token;
+        if (auth.data.user.role.id === 2022) {
+          Router.push({ pathname: "/pt/pemantauan" });
+          await createLog(auth.data.token, { aktivitas: "Berhasil Login" });
+          return;
+        } else if ([2020, 2021, 2023].includes(auth.data.user.role.id)) {
+          Router.push({ pathname: "/app/pemantauan" });
+          await createLog(auth.data.token, { aktivitas: "Berhasil Login" });
+          return;
+        } else {
+          this.setState({ error: "Akun tidak ada" });
+        }
+        this.setState({ loading: false });
+      }
+    } catch (error) {
+      this.setState({ loading: false });
+      this.setState({ error: error.response?.data.message || error.response });
+    }
+  };
 
-	/* Simplify error check */
-	hasError = (formName, inputName, method) => {
-		return this.state[formName] && this.state[formName].errors && this.state[formName].errors[inputName] && this.state[formName].errors[inputName][method];
-	};
+  /* Simplify error check */
+  hasError = (formName, inputName, method) => {
+    return (
+      this.state[formName] &&
+      this.state[formName].errors &&
+      this.state[formName].errors[inputName] &&
+      this.state[formName].errors[inputName][method]
+    );
+  };
 
-	render() {
-		return (
-			<Card className="card-login-over">
-				<img className="img-login-1" src="/static/img/logo-login.png" alt="Logo" />
-				<CardBody className="card-body">
-					{" "}
-					<h5 className="card-title text-left py-2 bg-gray border-radius-login">
-						<img className="icon-triangle" src="/static/img/icon-caution.png"></img>
-						<b>Login Menggunakan Akun PDDIKTI </b>
-					</h5>
-					{this.state.error}
-					<form onSubmit={this.onSubmit} method="post" name="formLogin">
-						<div className="form-group">
-							<label className="col-form-label">
-								Username <span className="star-color">*</span>
-							</label>
-							<Input type="text" name="username" invalid={this.hasError("formLogin", "username", "required")} onChange={this.validateOnChange} data-validate='["required"]' value={this.state.formLogin.username} />
-							{this.hasError("formLogin", "username", "required") && <span className="invalid-feedback">Field is required</span>}
-						</div>
-						<div className="form-group">
-							<label className="col-form-label">
-								Password <span className="star-color">*</span>
-							</label>
-							<Input
-								type="password"
-								id="id-password"
-								name="password"
-								invalid={this.hasError("formLogin", "password", "required")}
-								onChange={this.validateOnChange}
-								data-validate='["required"]'
-								value={this.state.formLogin.password}
-							/>
-							<span className="invalid-feedback">Field is required</span>
-						</div>
-						{/* <div className="required">* Required fields</div>
+  render() {
+    return (
+      <Card className="card-login-over">
+        <img
+          className="img-login-1"
+          src="/static/img/logo-login.png"
+          alt="Logo"
+        />
+        <CardBody className="card-body">
+          {" "}
+          <h5 className="card-title text-left py-2 bg-gray border-radius-login">
+            <img
+              className="icon-triangle"
+              src="/static/img/icon-caution.png"
+            ></img>
+            <b>Login Menggunakan Akun PDDIKTI </b>
+          </h5>
+          {this.state.error}
+          <form onSubmit={this.onSubmit} method="post" name="formLogin">
+            <div className="form-group">
+              <label className="col-form-label">
+                Username <span className="star-color">*</span>
+              </label>
+              <Input
+                type="text"
+                name="username"
+                invalid={this.hasError("formLogin", "username", "required")}
+                onChange={this.validateOnChange}
+                data-validate='["required"]'
+                value={this.state.formLogin.username}
+              />
+              {this.hasError("formLogin", "username", "required") && (
+                <span className="invalid-feedback">Field is required</span>
+              )}
+            </div>
+            <div className="form-group">
+              <label className="col-form-label">
+                Password <span className="star-color">*</span>
+              </label>
+              <Input
+                type="password"
+                id="id-password"
+                name="password"
+                invalid={this.hasError("formLogin", "password", "required")}
+                onChange={this.validateOnChange}
+                data-validate='["required"]'
+                value={this.state.formLogin.password}
+              />
+              <span className="invalid-feedback">Field is required</span>
+            </div>
+            {/* <div className="required">* Required fields</div>
 						<span>Login Menggunakan Akun PDDIKTI</span> */}
-						<div className="btn-radius">
-							<Button color type="submit" block className=" mt-3 btn-login">
-								<text className="text-login">
-									<b className="font-color-white">Login</b>
-								</text>
-							</Button>
-						</div>
-					</form>
-				</CardBody>
-			</Card>
-		);
-	}
+            <div className="btn-radius">
+              <Button color type="submit" block className=" mt-3 btn-login">
+                <text className="text-login">
+                  <b className="font-color-white">
+                    {" "}
+                    {this.state.loading ? (
+                      <div class="d-flex align-items-center">
+                        <strong>Login...</strong>
+                        <div
+                          class="spinner-border spinner-border-sm ml-auto"
+                          role="status"
+                          aria-hidden="true"
+                        ></div>
+                      </div>
+                    ) : (
+                      "Login"
+                    )}
+                  </b>
+                </text>
+              </Button>
+            </div>
+          </form>
+        </CardBody>
+      </Card>
+    );
+  }
 }
 
 const mapStateToProps = (state) => ({ user: state.user });
 const mapDispatchToProps = (dispatch) => ({
-	setUser: (payload) => dispatch({ type: "SET_USER", payload }),
-	setToken: (payload) => dispatch({ type: "SET_TOKEN", payload }),
-	setPT: (payload) => dispatch({ type: "SET_PT", payload }),
+  setUser: (payload) => dispatch({ type: "SET_USER", payload }),
+  setToken: (payload) => dispatch({ type: "SET_TOKEN", payload }),
+  setPT: (payload) => dispatch({ type: "SET_PT", payload }),
 });
 
 export default connect(mapStateToProps, mapDispatchToProps)(Login);

+ 1 - 1
pages/app/pelaporan/index.js

@@ -5,7 +5,7 @@ import { Row, Col, Button } from "reactstrap";
 import { getPelaporan } from "@/actions/pelaporan";
 import { getGraph, getExcel } from "@/actions/graph";
 import CaseProgress from "@/components/Pelaporan/CaseProgress";
-import TableLaporan from "@/components/Pelaporan/TableLaporan";
+import TableLaporan from "@/components/pelaporan/TableLaporan";
 import { connect } from "react-redux";
 import Loader from "@/components/Common/Loader";
 import Router from 'next/router'

+ 623 - 431
pages/laporan/new/index.js

@@ -7,7 +7,27 @@ import { createLaporanPublic } from "@/actions/pelaporan";
 import { notifLaporanBaru } from "@/actions/notifikasi";
 import Select from "react-select";
 import AsyncSelect from "react-select/async";
-import { Row, Col, FormGroup, Input, Card, CardBody, Button, CustomInput, Navbar, NavItem, NavLink, NavbarBrand, NavbarToggler, Nav, Collapse, Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
+import {
+  Row,
+  Col,
+  FormGroup,
+  Input,
+  Card,
+  CardBody,
+  Button,
+  CustomInput,
+  Navbar,
+  NavItem,
+  NavLink,
+  NavbarBrand,
+  NavbarToggler,
+  Nav,
+  Collapse,
+  Modal,
+  ModalHeader,
+  ModalBody,
+  ModalFooter,
+} from "reactstrap";
 import Link from "next/link";
 import ContentWrapper from "@/components/Layout/ContentWrapper";
 import { createPublicUser } from "@/actions/user";
@@ -19,466 +39,638 @@ import swal from "sweetalert2";
 import "react-toastify/dist/ReactToastify.css";
 
 const checkIfFilesAreTooBig = (files) => {
-	let valid = true;
-	if (files) {
-		files.map((file) => {
-			if (file.size > 15 * 1024 * 1024) {
-				valid = false;
-			}
-		});
-	}
-	return valid;
+  let valid = true;
+  if (files) {
+    files.map((file) => {
+      if (file.size > 15 * 1024 * 1024) {
+        valid = false;
+      }
+    });
+  }
+  return valid;
 };
 
 const checkIfFilesAreCorrectType = (files) => {
-	let valid = true;
-	if (files) {
-		files.map((file) => {
-			if (!["image/jpeg", "image/png"].includes(file.type)) {
-				valid = false;
-			}
-		});
-	}
-	return valid;
+  let valid = true;
+  if (files) {
+    files.map((file) => {
+      if (!["image/jpeg", "image/png"].includes(file.type)) {
+        valid = false;
+      }
+    });
+  }
+  return valid;
 };
 
 const laporanSchema = Yup.object().shape({
-	no_laporan: Yup.string().required(),
-	no_hp: Yup.number().required("Wajib Diisi"),
-	nama: Yup.string().notRequired(),
-	setuju: Yup.boolean().isTrue("Harap diceklis"),
-	alamat: Yup.string().min(3, "Minimal 3 huruf").max(200, "Maksimal 200 huruf").notRequired(),
-	keterangan: Yup.string().min(3, "Minimal 3 huruf").max(200, "Maksimal 200 huruf").required(""),
-	email: Yup.string().email().notRequired(),
-	pelanggaran_id: Yup.array().min(1, "Minimal terdapat 1 jenis pelanggaran").required(""),
-	pt_id: Yup.string().required(""),
-	foto: Yup.array().notRequired().test("filesize", "Maksimal ukuran foto 15mb", checkIfFilesAreTooBig).test("type", "harus jpeg/png", checkIfFilesAreCorrectType),
-	dokumen: Yup.array().min(1, " ").required().test("filesize", "Maksimal ukuran setiap dokumen 15mb", checkIfFilesAreTooBig),
-	is_private: Yup.boolean().notRequired(),
+  no_laporan: Yup.string().required(),
+  no_hp: Yup.number().notRequired(),
+  nama: Yup.string().notRequired(),
+  setuju: Yup.boolean().isTrue("Harap diceklis"),
+  alamat: Yup.string()
+    .min(3, "Minimal 3 huruf")
+    .max(200, "Maksimal 200 huruf")
+    .notRequired(),
+  keterangan: Yup.string()
+    .min(3, "Minimal 3 huruf")
+    .max(200, "Maksimal 200 huruf")
+    .required(""),
+  email: Yup.string().email().notRequired(),
+  pelanggaran_id: Yup.array()
+    .min(1, "Minimal terdapat 1 jenis pelanggaran")
+    .required(""),
+  pt_id: Yup.string().required(""),
+  foto: Yup.array()
+    .notRequired()
+    .test("filesize", "Maksimal ukuran foto 15mb", checkIfFilesAreTooBig)
+    .test("type", "harus jpeg/png", checkIfFilesAreCorrectType),
+  dokumen: Yup.array()
+    .min(0, " ")
+    .notRequired()
+    .test(
+      "filesize",
+      "Maksimal ukuran setiap dokumen 15mb",
+      checkIfFilesAreTooBig
+    ),
+  is_private: Yup.boolean().notRequired(),
 });
 
 const loadOptions = (inputValue, callback) => {
-	setTimeout(async () => {
-		const pt = await ptPublic({ search: inputValue });
-		const data = pt.data.map((e) => ({ value: e.id, label: e.nama, className: "State-ACT" }));
-		callback(data);
-	}, 1000);
+  setTimeout(async () => {
+    const pt = await ptPublic({ search: inputValue });
+    const data = pt.data.map((e) => ({
+      value: e.id,
+      label: e.nama,
+      className: "State-ACT",
+    }));
+    callback(data);
+  }, 1000);
 };
 
 const menu = [
-	{
-		title: "Home",
-		path: "/app",
-	},
-	{
-		title: "Buat Laporan",
-		path: "/laporan/new",
-	},
-	{
-		title: "Pemantauan",
-		path: "/pemantauan",
-	},
+  {
+    title: "Home",
+    path: "/app",
+  },
+  {
+    title: "Buat Laporan",
+    path: "/laporan/new",
+  },
+  {
+    title: "Pemantauan",
+    path: "/pemantauan",
+  },
 ];
 const selectInstanceId = 1;
 class App extends Component {
-	constructor(props) {
-		super(props);
-		this.state = {
-			isOpen: false,
-			inputValue: "",
-			pelaporanNumber: Math.floor(Date.now() * Math.random()),
-			nama: "",
-			alamat: "",
-			no_hp: "",
-			email: "",
-			fileIdentitas: null,
-			pelanggaran: [],
-			selectedPerguruanTinggi: {},
-			selectedJenis: [],
-			keteranganLaporan: "",
-			files: [],
-			isPrivate: false,
-			confirm: false,
-			msgError: [],
-			modal: false,
-			user: {},
-			kode: "",
-			error: null,
-			data: {},
-			token: "",
-		};
-	}
+  constructor(props) {
+    super(props);
+    this.state = {
+      isOpen: false,
+      inputValue: "",
+      pelaporanNumber: Math.floor(Date.now() * Math.random()),
+      nama: "",
+      alamat: "",
+      no_hp: "",
+      email: "",
+      fileIdentitas: null,
+      pelanggaran: [],
+      selectedPerguruanTinggi: {},
+      selectedJenis: [],
+      keteranganLaporan: "",
+      files: [],
+      isPrivate: false,
+      confirm: false,
+      msgError: [],
+      modal: false,
+      user: {},
+      kode: "",
+      error: null,
+      data: {},
+      token: "",
+    };
+  }
 
-	static getInitialProps = ({ pathname }) => ({ pathname });
+  static getInitialProps = ({ pathname }) => ({ pathname });
 
-	componentDidMount = async () => {
-		const pelanggaran = await getPelanggaranPublic();
-		this.setState({ pelanggaran });
-	};
+  componentDidMount = async () => {
+    const pelanggaran = await getPelanggaranPublic();
+    this.setState({ pelanggaran });
+  };
 
-	toggleModal = () => {
-		this.setState({ modal: !this.state.modal });
-	};
+  toggleModal = () => {
+    this.setState({ modal: !this.state.modal });
+  };
 
-	optionsJenisPelanggaran = (pelanggaran) => {
-		return pelanggaran.data.map((e) => ({ value: e._id, label: e.pelanggaran, className: "State-ACT" }));
-	};
+  optionsJenisPelanggaran = (pelanggaran) => {
+    return pelanggaran.data.map((e) => ({
+      value: e._id,
+      label: e.pelanggaran,
+      className: "State-ACT",
+    }));
+  };
 
-	setKeteranganPelaporan = (e) => {
-		this.setState({ keteranganLaporan: e.target.value });
-	};
+  setKeteranganPelaporan = (e) => {
+    this.setState({ keteranganLaporan: e.target.value });
+  };
 
-	handleChangeSelectJenis = (selectedJenis) => {
-		this.setState({ selectedJenis });
-	};
+  handleChangeSelectJenis = (selectedJenis) => {
+    this.setState({ selectedJenis });
+  };
 
-	handleChangeSelectPerguruanTinggi = (selectedPerguruanTinggi) => {
-		this.setState({ selectedPerguruanTinggi });
-	};
+  handleChangeSelectPerguruanTinggi = (selectedPerguruanTinggi) => {
+    this.setState({ selectedPerguruanTinggi });
+  };
 
-	handleInputChange = (newValue) => {
-		const inputValue = newValue.replace(/\W/g, "");
-		this.setState({ inputValue });
-		return inputValue;
-	};
+  handleInputChange = (newValue) => {
+    const inputValue = newValue.replace(/\W/g, "");
+    this.setState({ inputValue });
+    return inputValue;
+  };
 
-	handleKirim = async (data, { resetForm }) => {
-		const formdata = new FormData();
-		formdata.append("no_laporan", data.no_laporan);
-		formdata.append("pt_id", data.pt_id);
-		formdata.append("nama", data.nama);
-		formdata.append("email", data.email);
-		formdata.append("no_hp", data.no_hp);
-		formdata.append("alamat", data.alamat);
-		formdata.append("is_private", data.is_private);
-		formdata.append("keterangan", data.keterangan);
-		formdata.append("pelanggaran_id", data.pelanggaran_id.join(","));
-		formdata.append("foto", data.foto[0]);
+  handleKirim = async (data, { resetForm }) => {
+    const formdata = new FormData();
+    formdata.append("no_laporan", data.no_laporan);
+    formdata.append("pt_id", data.pt_id);
+    formdata.append("nama", data.nama);
+    formdata.append("email", data.email);
+    formdata.append("no_hp", data.no_hp);
+    formdata.append("alamat", data.alamat);
+    formdata.append("is_private", data.is_private);
+    formdata.append("keterangan", data.keterangan);
+    formdata.append("pelanggaran_id", data.pelanggaran_id.join(","));
+    formdata.append("foto", data.foto[0]);
 
-		if (data.dokumen.length > 0) {
-			Array.from(data.dokumen).forEach((e) => {
-				formdata.append("dokumen", e);
-			});
-		}
+    if (data.dokumen.length > 0) {
+      Array.from(data.dokumen).forEach((e) => {
+        formdata.append("dokumen", e);
+      });
+    }
 
-		const toastid = toast.loading("Please wait...");
-		const success = await createLaporanPublic(formdata);
-		if (!success) {
-			swal.fire({
-				title: 'Data tidak berhasil dikirim',
-				icon: 'error',
-				confirmButtonColor: '#6FB9DE',
-			})
-		} else {
-			swal.fire({
-				title: 'Data berhasil dikirim',
-				icon: 'success',
-				confirmButtonColor: '#6FB9DE',
-			})
-			Router.push("/laporan/new");
-		}
-	};
+    const toastid = toast.loading("Please wait...");
+    const success = await createLaporanPublic(formdata);
+    if (!success) {
+      swal.fire({
+        title: "Data tidak berhasil dikirim",
+        icon: "error",
+        confirmButtonColor: "#6FB9DE",
+      });
+    } else {
+      swal.fire({
+        title: "Data berhasil dikirim",
+        icon: "success",
+        confirmButtonColor: "#6FB9DE",
+      });
+      Router.push("/laporan/new");
+    }
+  };
 
-	createLaporan = async (token, kode = "") => {
-		const data = this.state.data;
-		const formdata = new FormData();
-		formdata.append("pt_id", data.pt_id);
-		formdata.append("keterangan", data.keterangan);
-		formdata.append("pelanggaran_id", data.pelanggaran_id.join(","));
-		if (kode) {
-			formdata.append("no_verifikasi", kode);
-		}
-		if (data.dokumen.length > 0) {
-			Array.from(data.dokumen).forEach((e) => {
-				formdata.append("dokumen", e);
-			});
-		}
+  createLaporan = async (token, kode = "") => {
+    const data = this.state.data;
+    const formdata = new FormData();
+    formdata.append("pt_id", data.pt_id);
+    formdata.append("keterangan", data.keterangan);
+    formdata.append("pelanggaran_id", data.pelanggaran_id.join(","));
+    if (kode) {
+      formdata.append("no_verifikasi", kode);
+    }
+    if (data.dokumen.length > 0) {
+      Array.from(data.dokumen).forEach((e) => {
+        formdata.append("dokumen", e);
+      });
+    }
 
-		// const toastid = toast.loading("Please wait...");
-		const success = await createLaporanPublic(token, formdata);
-		if (!success) {
-			// toast.update(toastid, { render: "All is not good", type: "error", isLoading: false, autoClose: true, closeButton: true });
-			swal.fire({
-				title: 'Kode verifikasi salah',
-				icon: 'error',
-				confirmButtonColor: '#6FB9DE',
-			})
-			this.setState({ error: "Kode verifikasi tidak valid" });
-		} else {
-			// toast.update(toastid, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
-			swal.fire({
-				title: 'Data berhasil dikirim',
-				icon: 'success',
-				confirmButtonColor: '#6FB9DE',
-			})
-			this.toggleModal();
-			Router.push("/laporan/new");
-		}
-	};
+    // const toastid = toast.loading("Please wait...");
+    const success = await createLaporanPublic(token, formdata);
+    if (!success) {
+      // toast.update(toastid, { render: "All is not good", type: "error", isLoading: false, autoClose: true, closeButton: true });
+      swal.fire({
+        title: "Kode verifikasi salah",
+        icon: "error",
+        confirmButtonColor: "#6FB9DE",
+      });
+      this.setState({ error: "Kode verifikasi tidak valid" });
+    } else {
+      // toast.update(toastid, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
+      swal.fire({
+        title: "Data berhasil dikirim",
+        icon: "success",
+        confirmButtonColor: "#6FB9DE",
+      });
+      this.toggleModal();
+      Router.push("/laporan/new");
+    }
+  };
 
-	createUser = async (data) => {
-		const formdata = new FormData();
-		formdata.append("no_laporan", data.no_laporan);
-		formdata.append("pt_id", data.pt_id);
-		if (data.nama) formdata.append("nama", data.nama);
-		if (data.email) formdata.append("email", data.email);
-		formdata.append("no_hp", data.no_hp);
-		if (data.alamat) formdata.append("alamat", data.alamat);
-		formdata.append("is_private", data.is_private);
-		if (data.foto.length > 0) formdata.append("foto", data.foto[0]);
-		return await createPublicUser(formdata);
-	};
+  createUser = async (data) => {
+    const formdata = new FormData();
+    formdata.append("no_laporan", data.no_laporan);
+    formdata.append("pt_id", data.pt_id);
+    if (data.nama) formdata.append("nama", data.nama);
+    if (data.email) formdata.append("email", data.email);
+    formdata.append("no_hp", data.no_hp);
+    if (data.alamat) formdata.append("alamat", data.alamat);
+    formdata.append("is_private", data.is_private);
+    if (data.foto.length > 0) formdata.append("foto", data.foto[0]);
+    return await createPublicUser(formdata);
+  };
 
-	render() {
-		const { selectedJenis, pelanggaran } = this.state;
-		return (
-			<div>
-				<ToastContainer />
-				<Navbar className="navbar-color" expand="md" dark>
-					<NavbarBrand href="/">
-						<img className="width-133" src="/static/img/Logo-Sidali.png" alt="App Logo" />
-					</NavbarBrand>
-					<NavbarToggler onClick={this.toggleCollapse} />
-					<Collapse isOpen={this.state.isOpen} navbar>
-						<Nav className="ml-auto" navbar>
-							{menu.map((e) => (
-								<NavItem active={e.path === this.props.pathname ? true : false}>
-									<Link href={e.path}>
-										<NavLink style={{ cursor: "pointer" }}>{e.title}</NavLink>
-									</Link>
-								</NavItem>
-							))}
-						</Nav>
-					</Collapse>
-				</Navbar>
-				<ContentWrapper>
-					<Row>
-						<Col lg={8} className="block-center d-block ">
-							<Card className="card-default">
-								<CardBody>
-									<Formik
-										initialValues={{
-											nama: "",
-											no_hp: "",
-											email: "",
-											alamat: "",
-											foto: [],
-											no_laporan: moment(new Date()).format("DDMM") + "" + Math.floor(Math.random() * 1000000),
-											pt_id: "",
-											pelanggaran_id: "",
-											keterangan: "",
-											dokumen: [],
-											setuju: false,
-											is_private: false,
-										}}
-										validationSchema={laporanSchema}
-										onSubmit={async (data) => {
-											this.toggleModal();
-											this.setState({ data, no_hp: data.no_hp });
-											const user = await this.createUser(data);
-											const token = user.data.token;
-											this.setState({ user, token });
-										}}
-									>
-										<Form className="form-horizontal">
-											<div class="header-1">
-												<h2 class="card-title-1">Identitas Pelapor</h2>
-											</div>
-											<FormGroup row></FormGroup>
-											<FormGroup row>
-												<label className="col-md-2 col-form-label">Nama Lengkap</label>
-												<div className="col-md-10">
-													<Field name="nama">{({ field }) => <Input type="text" {...field} />}</Field>
-													<ErrorMessage name="nama" component="div" className="form-text text-danger" />
-												</div>
-											</FormGroup>
-											<FormGroup row>
-												<label className="col-md-2 col-form-label">
-													Nomor Aktif<span className="star-color">*</span>
-												</label>
-												<div className="col-md-10">
-													<Field name="no_hp">{({ field, form }) => <Input type="tel" {...field} />}</Field>
-													<ErrorMessage name="no_hp" component="div" className="form-text text-danger" />
-												</div>
-											</FormGroup>
-											<FormGroup row>
-												<label className="col-md-2 col-form-label">Email</label>
-												<div className="col-md-10">
-													<Field name="email">{({ field }) => <Input type="email" {...field} />}</Field>
-													<ErrorMessage name="email" component="div" className="form-text text-danger" />
-												</div>
-											</FormGroup>
-											<FormGroup row>
-												<label className="col-md-2 col-form-label">Alamat</label>
-												<div className="col-md-10">
-													<Field name="alamat">{({ field }) => <Input type="textarea" {...field} />}</Field>
-													<ErrorMessage name="alamat" component="div" className="form-text text-danger" />
-												</div>
-											</FormGroup>
-											<FormGroup row>
-												<label className="col-md-2 col-form-label">Foto Kartu Identitas</label>
-												<div className="col-md-10">
-													<Field name="foto">{({ field, form }) => <Input type="file" onChange={(e) => form.setFieldValue(field.name, Array.from(e.currentTarget.files))} />}</Field>
-													<ErrorMessage name="foto" component="div" className="form-text text-danger" />
-													<p className="mrgn-top-5">
-														Ukuran setiap dokumen maksimal 15mb
-													</p>
-												</div>
-												<div className="col-xl-10">
-													<div className="checkbox c-checkbox">
-														<label>
-															<Field name="is_private">{({ field }) => <Input type="checkbox" {...field} />}</Field>
-															<span className="fa fa-check"></span>
-															<text>Klik jika ingin merahasiakan identitas anda</text>
-														</label>
-													</div>
-												</div>
-											</FormGroup>
-											<div class="header-1">
-												<h2 class="card-title-1">Detail Laporan<span className="font-20">(wajib diisi)</span></h2>
-											</div>
-											{/* <p className="lead bb">Detail Laporan</p> */}
-											<FormGroup row>
-												<label className="col-md-2 col-form-label">Nomor Pelaporan</label>
-												<div className="col-md-10">
-													<Field name="no_laporan">{({ field }) => <Input disabled type="text" {...field} />}</Field>
-													<ErrorMessage name="no_laporan" component="div" className="form-text text-danger" />
-												</div>
-											</FormGroup>
-											<FormGroup row>
-												<label className="col-md-2 col-form-label">
-													Perguruan Tinggi yang Dilaporkan<span className="star-color"></span>
-												</label>
-												<div className="col-md-10">
-													<Field name="pt_id">
-														{({ field, form }) => (
-															<AsyncSelect
-																cacheOptions
-																loadOptions={loadOptions}
-																defaultOptions
-																onChange={(e) => {
-																	this.handleChangeSelectPerguruanTinggi(e);
-																	form.setFieldValue(field.name, e.value);
-																}}
-																onInputChange={this.handleInputChange}
-															/>
-														)}
-													</Field>
-													<ErrorMessage name="pt_id" component="div" className="form-text text-danger" />
-												</div>
-											</FormGroup>
-											<FormGroup row>
-												<label className="col-md-2 col-form-label">
-													Jenis Pelanggaran<span className="star-color"></span>
-												</label>
-												<div className="col-md-10">
-													<Field name="pelanggaran_id">
-														{({ field, form }) => (
-															<Select
-																instanceId={selectInstanceId + 1}
-																isMulti
-																value={selectedJenis}
-																onChange={(e) => {
-																	this.handleChangeSelectJenis(e);
-																	form.setFieldValue(
-																		field.name,
-																		e.map((e) => e.value)
-																	);
-																}}
-																options={pelanggaran.data ? this.optionsJenisPelanggaran(pelanggaran) : []}
-																required
-															/>
-														)}
-													</Field>
-													<ErrorMessage name="pelanggaran_id" component="div" className="form-text text-danger" />
-												</div>
-											</FormGroup>
-											<FormGroup row>
-												<label className="col-md-2 col-form-label">
-													Keterangan Laporan<span className="star-color"></span>
-												</label>
-												<div className="col-md-10">
-													<Field name="keterangan">{({ field }) => <Input type="textarea" {...field} />}</Field>
-													<ErrorMessage name="keterangan" component="div" className="form-text text-danger" />
-												</div>
-											</FormGroup>
-											<FormGroup row>
-												<label className="col-md-2 col-form-label">
-													File Pendukung
-												</label>
-												<div className="col-md-10">
-													<Field name="dokumen">{({ field, form }) => <Input type="file" multiple onChange={(e) => form.setFieldValue(field.name, Array.from(e.currentTarget.files))} />}</Field>
-													<ErrorMessage name="dokumen" component="div" className="form-text text-danger" />
-													<p className="mrgn-top-5">
-														Ukuran setiap dokumen maksimal 15mb
-													</p>
-												</div>
-											</FormGroup>
-											<FormGroup row>
-												<div className="col-xl-10">
-													<div className="checkbox c-checkbox">
-														<label>
-															<Field name="setuju">{({ field }) => <Input type="checkbox" {...field} />}</Field>
-															<span className="fa fa-check"></span>
-															<text>Klik jika data yang anda laporkan sudah benar</text>
-															<ErrorMessage name="setuju" component="div" className="form-text text-danger" />
-														</label>
-													</div>
-												</div>
-											</FormGroup>
-											<FormGroup row>
-												<div className="posisi-btn-1 btn-radius">
-													<Button className="button-kirimlaporan" color type="submit">
-														<h3 className="text-kirimlaporan font-color-white">Kirim Laporan</h3>
-													</Button>
-												</div>
-											</FormGroup>
-										</Form>
-									</Formik>
-								</CardBody>
-							</Card>
-						</Col>
-					</Row>
-					<Modal isOpen={this.state.modal}>
-						<form className="form-horizontal">
-							<ModalBody>
-								<FormGroup>
-									<label>Masukkan Kode Verifikasi</label>
-									<div>
-										<Input onChange={(e) => this.setState({ kode: e.target.value })} type="text" />
-									</div>
-									<p>*Kode verifikasi terkirim ke nomor WA {this.state.no_hp}</p>
-									{this.state.error && <div className="form-text text-danger">{this.state.error}</div>}
-								</FormGroup>
-							</ModalBody>
-							<ModalFooter>
-								<Button
-									color="info"
-									onClick={async () => {
-										await this.createLaporan(this.state.token);
-									}}
-								>
-									Buat Laporan Tanpa Kode Verifikasi
-								</Button>
-								<Button
-									color="primary"
-									onClick={async () => {
-										if (this.state.kode) {
-											await this.createLaporan(this.state.token, this.state.kode);
-										} else {
-											this.setState({ error: "Kode verifikasi harus diisi" });
-										}
-									}}
-								>
-									Kirim
-								</Button>
-							</ModalFooter>
-						</form>
-					</Modal>
-				</ContentWrapper>
-			</div >
-		);
-	}
+  render() {
+    const { selectedJenis, pelanggaran } = this.state;
+    return (
+      <div>
+        <ToastContainer />
+        <Navbar className="navbar-color" expand="md" dark>
+          <NavbarBrand href="/">
+            <img
+              className="width-133"
+              src="/static/img/Logo-Sidali.png"
+              alt="App Logo"
+            />
+          </NavbarBrand>
+          <NavbarToggler onClick={this.toggleCollapse} />
+          <Collapse isOpen={this.state.isOpen} navbar>
+            <Nav className="ml-auto" navbar>
+              {menu.map((e) => (
+                <NavItem active={e.path === this.props.pathname ? true : false}>
+                  <Link href={e.path}>
+                    <NavLink style={{ cursor: "pointer" }}>{e.title}</NavLink>
+                  </Link>
+                </NavItem>
+              ))}
+            </Nav>
+          </Collapse>
+        </Navbar>
+        <ContentWrapper>
+          <Row>
+            <Col lg={8} className="block-center d-block ">
+              <Card className="card-default">
+                <CardBody>
+                  <Formik
+                    initialValues={{
+                      nama: "",
+                      no_hp: "",
+                      email: "",
+                      alamat: "",
+                      foto: [],
+                      no_laporan:
+                        moment(new Date()).format("DDMM") +
+                        "" +
+                        Math.floor(Math.random() * 1000000),
+                      pt_id: "",
+                      pelanggaran_id: "",
+                      keterangan: "",
+                      dokumen: [],
+                      setuju: false,
+                      is_private: false,
+                    }}
+                    validationSchema={laporanSchema}
+                    onSubmit={async (data) => {
+                      this.toggleModal();
+                      this.setState({ data, no_hp: data.no_hp });
+                      const user = await this.createUser(data);
+                      const token = user.data.token;
+                      this.setState({ user, token });
+                    }}
+                  >
+                    <Form className="form-horizontal">
+                      <div class="header-1">
+                        <h2 class="card-title-1">Identitas Pelapor</h2>
+                      </div>
+                      <FormGroup row></FormGroup>
+                      <FormGroup row>
+                        <label className="col-md-2 col-form-label">
+                          Nama Lengkap
+                        </label>
+                        <div className="col-md-10">
+                          <Field name="nama">
+                            {({ field }) => <Input type="text" {...field} />}
+                          </Field>
+                          <ErrorMessage
+                            name="nama"
+                            component="div"
+                            className="form-text text-danger"
+                          />
+                        </div>
+                      </FormGroup>
+                      <FormGroup row>
+                        <label className="col-md-2 col-form-label">
+                          Nomor Aktif
+                          <span className="star-color">
+                            {" "}
+                            &#40;opsional&#41;
+                          </span>
+                        </label>
+                        <div className="col-md-10">
+                          <Field name="no_hp">
+                            {({ field, form }) => (
+                              <Input type="tel" {...field} />
+                            )}
+                          </Field>
+                          <ErrorMessage
+                            name="no_hp"
+                            component="div"
+                            className="form-text text-danger"
+                          />
+                        </div>
+                      </FormGroup>
+                      <FormGroup row>
+                        <label className="col-md-2 col-form-label">Email</label>
+                        <div className="col-md-10">
+                          <Field name="email">
+                            {({ field }) => <Input type="email" {...field} />}
+                          </Field>
+                          <ErrorMessage
+                            name="email"
+                            component="div"
+                            className="form-text text-danger"
+                          />
+                        </div>
+                      </FormGroup>
+                      <FormGroup row>
+                        <label className="col-md-2 col-form-label">
+                          Alamat
+                        </label>
+                        <div className="col-md-10">
+                          <Field name="alamat">
+                            {({ field }) => (
+                              <Input type="textarea" {...field} />
+                            )}
+                          </Field>
+                          <ErrorMessage
+                            name="alamat"
+                            component="div"
+                            className="form-text text-danger"
+                          />
+                        </div>
+                      </FormGroup>
+                      <FormGroup row>
+                        <label className="col-md-2 col-form-label">
+                          Foto Kartu Identitas
+                        </label>
+                        <div className="col-md-10">
+                          <Field name="foto">
+                            {({ field, form }) => (
+                              <Input
+                                type="file"
+                                onChange={(e) =>
+                                  form.setFieldValue(
+                                    field.name,
+                                    Array.from(e.currentTarget.files)
+                                  )
+                                }
+                              />
+                            )}
+                          </Field>
+                          <ErrorMessage
+                            name="foto"
+                            component="div"
+                            className="form-text text-danger"
+                          />
+                          <p className="mrgn-top-5">
+                            Ukuran setiap dokumen maksimal 15mb
+                          </p>
+                        </div>
+                        <div className="col-xl-10">
+                          <div className="checkbox c-checkbox">
+                            <label>
+                              <Field name="is_private">
+                                {({ field }) => (
+                                  <Input type="checkbox" {...field} />
+                                )}
+                              </Field>
+                              <span className="fa fa-check"></span>
+                              <text>
+                                Klik jika ingin merahasiakan identitas anda
+                              </text>
+                            </label>
+                          </div>
+                        </div>
+                      </FormGroup>
+                      <div class="header-1">
+                        <h2 class="card-title-1">
+                          Detail Laporan
+                          {/* <span className="font-20">(wajib diisi)</span> */}
+                        </h2>
+                      </div>
+                      {/* <p className="lead bb">Detail Laporan</p> */}
+                      <FormGroup row>
+                        <label className="col-md-2 col-form-label">
+                          Nomor Pelaporan
+                        </label>
+                        <div className="col-md-10">
+                          <Field name="no_laporan">
+                            {({ field }) => (
+                              <Input disabled type="text" {...field} />
+                            )}
+                          </Field>
+                          <ErrorMessage
+                            name="no_laporan"
+                            component="div"
+                            className="form-text text-danger"
+                          />
+                        </div>
+                      </FormGroup>
+                      <FormGroup row>
+                        <label className="col-md-2 col-form-label">
+                          Perguruan Tinggi yang Dilaporkan
+                          <span className="star-color"></span>
+                        </label>
+                        <div className="col-md-10">
+                          <Field name="pt_id">
+                            {({ field, form }) => (
+                              <AsyncSelect
+                                cacheOptions
+                                loadOptions={loadOptions}
+                                defaultOptions
+                                onChange={(e) => {
+                                  this.handleChangeSelectPerguruanTinggi(e);
+                                  form.setFieldValue(field.name, e.value);
+                                }}
+                                onInputChange={this.handleInputChange}
+                              />
+                            )}
+                          </Field>
+                          <ErrorMessage
+                            name="pt_id"
+                            component="div"
+                            className="form-text text-danger"
+                          />
+                        </div>
+                      </FormGroup>
+                      <FormGroup row>
+                        <label className="col-md-2 col-form-label">
+                          Jenis Pelanggaran<span className="star-color"></span>
+                        </label>
+                        <div className="col-md-10">
+                          <Field name="pelanggaran_id">
+                            {({ field, form }) => (
+                              <Select
+                                instanceId={selectInstanceId + 1}
+                                isMulti
+                                value={selectedJenis}
+                                onChange={(e) => {
+                                  this.handleChangeSelectJenis(e);
+                                  form.setFieldValue(
+                                    field.name,
+                                    e.map((e) => e.value)
+                                  );
+                                }}
+                                options={
+                                  pelanggaran.data
+                                    ? this.optionsJenisPelanggaran(pelanggaran)
+                                    : []
+                                }
+                                required
+                              />
+                            )}
+                          </Field>
+                          <ErrorMessage
+                            name="pelanggaran_id"
+                            component="div"
+                            className="form-text text-danger"
+                          />
+                        </div>
+                      </FormGroup>
+                      <FormGroup row>
+                        <label className="col-md-2 col-form-label">
+                          Keterangan Laporan<span className="star-color"></span>
+                        </label>
+                        <div className="col-md-10">
+                          <Field name="keterangan">
+                            {({ field }) => (
+                              <Input type="textarea" {...field} />
+                            )}
+                          </Field>
+                          <ErrorMessage
+                            name="keterangan"
+                            component="div"
+                            className="form-text text-danger"
+                          />
+                        </div>
+                      </FormGroup>
+                      <FormGroup row>
+                        <label className="col-md-2 col-form-label">
+                          File Pendukung
+                        </label>
+                        <div className="col-md-10">
+                          <Field name="dokumen">
+                            {({ field, form }) => (
+                              <Input
+                                type="file"
+                                multiple
+                                onChange={(e) =>
+                                  form.setFieldValue(
+                                    field.name,
+                                    Array.from(e.currentTarget.files)
+                                  )
+                                }
+                              />
+                            )}
+                          </Field>
+                          <ErrorMessage
+                            name="dokumen"
+                            component="div"
+                            className="form-text text-danger"
+                          />
+                          <p className="mrgn-top-5">
+                            Ukuran setiap dokumen maksimal 15mb
+                          </p>
+                        </div>
+                      </FormGroup>
+                      <FormGroup row>
+                        <div className="col-xl-10">
+                          <div className="checkbox c-checkbox">
+                            <label>
+                              <Field name="setuju">
+                                {({ field }) => (
+                                  <Input type="checkbox" {...field} />
+                                )}
+                              </Field>
+                              <span className="fa fa-check"></span>
+                              <text>
+                                Klik jika data yang anda laporkan sudah benar
+                              </text>
+                              <ErrorMessage
+                                name="setuju"
+                                component="div"
+                                className="form-text text-danger"
+                              />
+                            </label>
+                          </div>
+                        </div>
+                      </FormGroup>
+                      <FormGroup row>
+                        <div className="posisi-btn-1 btn-radius">
+                          <Button
+                            className="button-kirimlaporan"
+                            color
+                            type="submit"
+                          >
+                            <h3 className="text-kirimlaporan font-color-white">
+                              Kirim Laporan
+                            </h3>
+                          </Button>
+                        </div>
+                      </FormGroup>
+                    </Form>
+                  </Formik>
+                </CardBody>
+              </Card>
+            </Col>
+          </Row>
+          <Modal isOpen={this.state.modal}>
+            <form className="form-horizontal">
+              <ModalBody>
+                <FormGroup>
+                  <label>Masukkan Kode Verifikasi</label>
+                  <div>
+                    <Input
+                      onChange={(e) => this.setState({ kode: e.target.value })}
+                      type="text"
+                    />
+                  </div>
+                  <p>
+                    *Kode verifikasi terkirim ke nomor WA {this.state.no_hp}
+                  </p>
+                  {this.state.error && (
+                    <div className="form-text text-danger">
+                      {this.state.error}
+                    </div>
+                  )}
+                </FormGroup>
+              </ModalBody>
+              <ModalFooter>
+                <Button
+                  color="info"
+                  onClick={async () => {
+                    await this.createLaporan(this.state.token);
+                  }}
+                >
+                  Buat Laporan Tanpa Kode Verifikasi
+                </Button>
+                <Button
+                  color="primary"
+                  onClick={async () => {
+                    if (this.state.kode) {
+                      await this.createLaporan(
+                        this.state.token,
+                        this.state.kode
+                      );
+                    } else {
+                      this.setState({ error: "Kode verifikasi harus diisi" });
+                    }
+                  }}
+                >
+                  Kirim
+                </Button>
+              </ModalFooter>
+            </form>
+          </Modal>
+        </ContentWrapper>
+      </div>
+    );
+  }
 }
 
 App.Layout = BasePage;