yazid138 преди 3 години
родител
ревизия
185f8c8812
променени са 47 файла, в които са добавени 848 реда и са изтрити 514 реда
  1. 5 11
      actions/banding.js
  2. 5 6
      actions/cabutSanksi.js
  3. 3 4
      actions/docPerbaikan.js
  4. 10 2
      actions/sanksi.js
  5. 3 4
      components/Banding/Riwayat.js
  6. 6 6
      components/Banding/TableSanksi.js
  7. 4 6
      components/DocPerbaikan/Riwayat.js
  8. 4 4
      components/Extras/calendar.view.js
  9. 2 0
      components/Layout/Header.js
  10. 11 2
      components/Layout/Menu.js
  11. 11 2
      components/Layout/MenuLLDIKTI.js
  12. 1 5
      components/Main/DetailLaporan.js
  13. 1 2
      components/Main/TableSanksi.js
  14. 5 6
      components/PT/DocPerbaikan/Riwayat.js
  15. 31 28
      components/PT/JawabanBanding/DetailJawaban.js
  16. 6 7
      components/PT/JawabanBanding/TableSanksiJawaban.js
  17. 5 7
      components/PT/JawabanKeberatan/DetailJawaban.js
  18. 20 16
      components/PT/JawabanKeberatan/ModalPermohonan.js
  19. 5 7
      components/PT/JawabanKeberatan/Riwayat.js
  20. 6 6
      components/PT/JawabanPencabutanSanksi/TableSanksiJawaban.js
  21. 0 1
      components/PT/Keberatan/Riwayat.js
  22. 3 1
      components/Pemeriksaan/InputEvaluasi.js
  23. 67 0
      components/Pemeriksaan/TableLaporan.js
  24. 7 8
      components/PencabutanSanksi/Riwayat.js
  25. 6 6
      components/PencabutanSanksi/TableSanksi.js
  26. 67 0
      components/Penjadwalan/TableLaporan.js
  27. 2 2
      components/Sanksi/TableLaporan.js
  28. 8 0
      package-lock.json
  29. 1 0
      package.json
  30. 119 78
      pages/app/banding/detail.js
  31. 6 3
      pages/app/banding/index.js
  32. 4 4
      pages/app/keberatan/detail.js
  33. 14 14
      pages/app/pemantauan-perbaikan/detail.js
  34. 4 6
      pages/app/pemantauan-perbaikan/index.js
  35. 1 1
      pages/app/pemeriksaan/index.js
  36. 134 91
      pages/app/pencabutan-sanksi/detail.js
  37. 4 6
      pages/app/pencabutan-sanksi/index.js
  38. 1 1
      pages/app/penjadwalan/index.js
  39. 110 42
      pages/pt/dokumen-perbaikan/detail.js
  40. 1 1
      pages/pt/dokumen-perbaikan/index.js
  41. 16 14
      pages/pt/jawaban-banding/detail.js
  42. 1 1
      pages/pt/jawaban-banding/index.js
  43. 22 20
      pages/pt/jawaban-keberatan/detail.js
  44. 27 28
      pages/pt/jawaban-pencabutan-sanksi/detail.js
  45. 1 1
      pages/pt/jawaban-pencabutan-sanksi/index.js
  46. 2 2
      pages/pt/keberatan/detail.js
  47. 76 52
      pages/pt/pencabutan-sanksi/detail.js

+ 5 - 11
actions/banding.js

@@ -1,27 +1,21 @@
-import { post } from "../config/request";
+import axios from "../config/axios";
 
-export const addBanding = async ({ noSanksi, ptId }, data) => {
+export const addBanding = async (token, id, data) => {
 	try {
-		const res = await post(`/banding/add?noSanksi=${noSanksi}&ptId=${ptId}`, data);
-		console.log(res);
-		// addLog({ status: "SUCCESS", action: "CREATE", from: { id: result.added._id, data: "banding" }, description: "membuat permohonan banding" });
+		const res = await axios.post(`/sanksi/banding/create/${id}`, data, { headers: { Authorization: token } });
 		return res.data;
 	} catch (error) {
 		console.log("error", error);
-		// addLog({ status: "FAIL", action: "ADD", from: { data: "banding" }, description: error.message || "membuat permohonan banding" });
 		return false;
 	}
 };
 
-export const addJawabanBanding = async ({ noSanksi, ptId }, data) => {
+export const addJawabanBanding = async (token, id, data) => {
 	try {
-		const res = await post(`/banding/jawaban/add?noSanksi=${noSanksi}&ptId=${ptId}`, data);
-		console.log(res);
-		// addLog({ status: "SUCCESS", action: "CREATE", from: { id: result.added._id, data: "banding" }, description: "membuat permohonan banding" });
+		const res = await axios.post(`/sanksi/banding/jawaban/create/${id}`, data, { headers: { Authorization: token } });
 		return res.data;
 	} catch (error) {
 		console.log("error", error);
-		// addLog({ status: "FAIL", action: "ADD", from: { data: "banding" }, description: error.message || "membuat permohonan banding" });
 		return false;
 	}
 };

+ 5 - 6
actions/cabutSanksi.js

@@ -1,9 +1,9 @@
 import { post } from "../config/request";
+import axios from "../config/axios";
 
-export const addCabutSanksi = async ({ noSanksi, ptId }, data) => {
+export const addCabutSanksi = async (token, id, data) => {
 	try {
-		const res = await post(`/cabut-sanksi/add?noSanksi=${noSanksi}&ptId=${ptId}`, data);
-		console.log(res);
+		const res = await axios.post(`/sanksi/cabut-sanksi/create/${id}`, data, { headers: { Authorization: token } });
 		return res.data;
 	} catch (error) {
 		console.log("error", error);
@@ -11,10 +11,9 @@ export const addCabutSanksi = async ({ noSanksi, ptId }, data) => {
 	}
 };
 
-export const addJawabanCabutSanksi = async ({ noSanksi, ptId }, data) => {
+export const addJawabanCabutSanksi = async (token, id, data) => {
 	try {
-		const res = await post(`/cabut-sanksi/jawaban/add?noSanksi=${noSanksi}&ptId=${ptId}`, data);
-		console.log(res);
+		const res = await axios.post(`/sanksi/cabut-sanksi/jawaban/create/${id}`, data, { headers: { Authorization: token } });
 		return res.data;
 	} catch (error) {
 		console.log("error", error);

+ 3 - 4
actions/docPerbaikan.js

@@ -1,9 +1,8 @@
-import { post } from "../config/request";
+import axios from "../config/axios";
 
-export const addDocPerbaikan = async ({ noSanksi, ptId }, data) => {
+export const addDocPerbaikan = async (token, id, data) => {
 	try {
-		const res = await post(`/doc-perbaikan/add?noSanksi=${noSanksi}&ptId=${ptId}`, data);
-		console.log(res);
+		const res = await axios.post(`/sanksi/perbaikan/add/${id}`, data, { headers: { Authorization: token } });
 		return res.data;
 	} catch (error) {
 		console.log("error", error);

+ 10 - 2
actions/sanksi.js

@@ -28,9 +28,17 @@ export const getSanksi = async (token, query = {}) => {
 	}
 };
 
-export const getOneSanksi = async (token, id) => {
+export const getOneSanksi = async (token, id, query = {}) => {
 	try {
-		const res = await axiosAPI.get(`/sanksi/${id}`, { headers: { Authorization: token } });
+		let url = `/sanksi/${id}`;
+		if (query != {}) {
+			const { banding } = query;
+			url += "?";
+			const parseURL = [];
+			if (banding) parseURL.push(`banding=true`);
+			url += parseURL.join("&");
+		}
+		const res = await axiosAPI.get(url, { headers: { Authorization: token } });
 		return res.data;
 	} catch (error) {
 		console.log("error", error);

+ 3 - 4
components/Banding/Riwayat.js

@@ -1,7 +1,6 @@
 import Datatable from "@/components/Tables/Datatable";
 import moment from "moment";
 import { Card, CardHeader, CardBody, CardTitle } from "reactstrap";
-import { API_URL } from "@/env";
 
 function Riwayat({ data }) {
 	return (
@@ -25,11 +24,11 @@ function Riwayat({ data }) {
 									<td>{moment(data.createAt).format("DD MMMM YYYY")}</td>
 									<td>{data.status}</td>
 									<td>
-										{data.files.map((e) => (
+										{data.dokumen.map((e) => (
 											<>
 												<em className="fa-lg far fa-file-code"></em>
-												<a className="text-muted" href={API_URL + e.path} target="_blank" download={e.name}>
-													{e.name}
+												<a className="text-muted" href={e.path} target="_blank" download={e.judul}>
+													{e.judul}
 												</a>
 											</>
 										))}

+ 6 - 6
components/Banding/TableSanksi.js

@@ -23,25 +23,25 @@ function TableSanksi({ listData, to, linkName }) {
 								? listData.map((data) => {
 										return (
 											<tr key={data._id}>
-												<td>{data.sanksi.no_sanksi}</td>
+												<td>{data.no_sanksi}</td>
 												<td>
 													<div className="media align-items-center">
 														<div className="media-body d-flex">
 															<div>
-																<h4 className="m-0">{data.pt.nama}</h4>
-																<p>{data.description.length > 25 ? data.description.substring(0, 25) + "..." : data.description}</p>
+																<h4 className="m-0">{data.laporan.pt.nama}</h4>
+																<p>{data.keterangan.length > 25 ? data.keterangan.substring(0, 25) + "..." : data.keterangan}</p>
 															</div>
 														</div>
 													</div>
 												</td>
-												<td>{moment(data.sanksi.createdAt).fromNow()}</td>
-												<td>{data.sanksi.banding.jawaban ? <div className="badge badge-info">Sudah Dijawab</div> : <div className="badge badge-danger">Belum Dijawab</div>}</td>
+												<td>{moment(data.createdAt).fromNow()}</td>
+												<td>{data.jawaban.banding ? <div className="badge badge-info">Sudah Dijawab</div> : <div className="badge badge-danger">Belum Dijawab</div>}</td>
 												<td>
 													<div className="ml-auto">
 														<Link
 															href={{
 																pathname: to,
-																query: { noSanksi: data.sanksi.no_sanksi, ptId: data.pt_id },
+																query: { id: data._id },
 															}}
 														>
 															<Button color="primary" size="sm">

+ 4 - 6
components/DocPerbaikan/Riwayat.js

@@ -1,10 +1,8 @@
 import Datatable from "@/components/Tables/Datatable";
 import moment from "moment";
 import { Card, CardHeader, CardBody, CardTitle } from "reactstrap";
-import { API_URL } from "@/env";
 
 function Riwayat({ data }) {
-	console.log(data);
 	return (
 		<Card className="card-default">
 			<CardHeader>
@@ -25,13 +23,13 @@ function Riwayat({ data }) {
 								? data.map((value) => (
 										<tr>
 											<td>{moment(value.createAt).format("DD MMMM YYYY")}</td>
-											<td>{value.description}</td>
+											<td>{value.keterangan}</td>
 											<td>
-												{value.files.map((e) => (
+												{value.dokumen.map((e) => (
 													<>
 														<em className="fa-lg far fa-file-code"></em>
-														<a className="text-muted" href={API_URL + e.path} target="_blank" download={e.name}>
-															{e.name}
+														<a className="text-muted" href={e.path} target="_blank" download={e.judul}>
+															{e.judul}
 														</a>
 													</>
 												))}

+ 4 - 4
components/Extras/calendar.view.js

@@ -118,11 +118,11 @@ class Calendar extends Component {
 	handleEventCalendar = async (data) => {
 		const { query, token } = this.props;
 		const { id } = query;
-		const { color } = this.state;
+		const { color, laporan } = this.state;
 
 		await toast.promise(
 			updateJadwal(token, id, {
-				judul: data.judul,
+				judul: "No.Laporan " + laporan.data.no_laporan + " - " + data.judul,
 				dari_tanggal: data.dari_tanggal,
 				sampai_tanggal: data.sampai_tanggal,
 				warna: color,
@@ -223,7 +223,7 @@ class Calendar extends Component {
 													<Formik
 														enableReinitialize={true}
 														initialValues={{
-															judul: laporan.data?.jadwal?.judul || "",
+															judul: laporan.data?.jadwal?.judul ? laporan.data.jadwal.judul.split("- ")[1] : "",
 															dari_tanggal: laporan.data?.jadwal?.dari_tanggal ? moment(laporan.data.jadwal.dari_tanggal) : "",
 															sampai_tanggal: laporan.data?.jadwal?.sampai_tanggal ? moment(laporan.data.jadwal.sampai_tanggal) : "",
 														}}
@@ -238,7 +238,7 @@ class Calendar extends Component {
 																		{this.state.color}
 																	</div>
 																</FormGroup>
-																
+
 																<FormGroup>
 																	<label className="col-form-label">Judul</label>
 																	<Field name="judul">{({ field, form }) => <Input type="text" placeholder="judul" {...field} />}</Field>

+ 2 - 0
components/Layout/Header.js

@@ -59,6 +59,7 @@ class Header extends Component {
 		e.preventDefault();
 		// await logout();
 		this.props.tokenNull();
+		this.props.userNull();
 		// if (cek.success) {
 		Router.push({ pathname: "/app" });
 		// }
@@ -225,6 +226,7 @@ const mapStateToProps = (state) => ({ settings: state.settings });
 const mapDispatchToProps = (dispatch) => ({
 	actions: bindActionCreators(actions, dispatch),
 	tokenNull: () => dispatch({ type: "SET_TOKEN", payload: null }),
+	userNull: () => dispatch({ type: "SET_USER", payload: null }),
 });
 
 export default connect(mapStateToProps, mapDispatchToProps)(Header);

+ 11 - 2
components/Layout/Menu.js

@@ -11,9 +11,18 @@ const Menu = [
 	},
 	{
 		name: "Pelaporan",
-		path: "/app/pelaporan",
 		icon: "icon-notebook",
-		translate: "sidebar.nav.PELAPORAN",
+		translate: "sidebar.nav.LAPORAN",
+		submenu: [
+			{
+				name: "List Laporan",
+				path: "/app/pelaporan",
+			},
+			{
+				name: "Laporan ditutup",
+				path: "/app/laporan-ditutup",
+			},
+		],
 	},
 	{
 		name: "Penjadwalan Evaluasi",

+ 11 - 2
components/Layout/MenuLLDIKTI.js

@@ -11,9 +11,18 @@ const Menu = [
 	},
 	{
 		name: "Pelaporan",
-		path: "/app/pelaporan",
 		icon: "icon-notebook",
-		translate: "sidebar.nav.PELAPORAN",
+		translate: "sidebar.nav.LAPORAN",
+		submenu: [
+			{
+				name: "List Laporan",
+				path: "/app/pelaporan",
+			},
+			{
+				name: "Laporan ditutup",
+				path: "/app/laporan-ditutup",
+			},
+		],
 	},
 	{
 		name: "Penjadwalan Evaluasi",

+ 1 - 5
components/Main/DetailLaporan.js

@@ -1,15 +1,11 @@
-import React, { useEffect, useState } from "react";
 import Scrollable from "@/components/Common/Scrollable";
 import moment from "moment";
 import { Col, FormGroup } from "reactstrap";
-import { useSelector } from "react-redux";
 
 function DetailLaporan({ data, noTitle = false, noStatus = false }) {
-	const user = useSelector((state) => state.user);
-
 	return (
 		<>
-			{(data.user.isPrivate || user.role.id === 2020) && (
+			{(!data.user.isPrivate || data.user.role.id === 2020 || data.user.role.id === 2021) && (
 				<>
 					{noTitle ? "" : <p className="lead bb">Identitas Pelapor - {data.user.isPublic ? "Umum" : "Internal"}</p>}
 					<FormGroup row>

+ 1 - 2
components/Main/TableSanksi.js

@@ -14,7 +14,7 @@ function TableSanksi({ listData, to, linkName }) {
 								<tr>
 									<th>Nomor Sanksi</th>
 									<th>Keterangan Sanksi</th>
-									{listData?.user.nama && <th>Dibuat Oleh</th>}
+									{/* {listData?.user.nama && <th>Dibuat Oleh</th>} */}
 									<th>Created</th>
 									<th></th>
 								</tr>
@@ -35,7 +35,6 @@ function TableSanksi({ listData, to, linkName }) {
 															</div>
 														</div>
 													</td>
-													{data.user?.nama && <td>{data.user.nama}</td>}
 													<td>{moment(data.createdAt).fromNow()}</td>
 													<td>
 														<div className="ml-auto">

+ 5 - 6
components/PT/DocPerbaikan/Riwayat.js

@@ -1,7 +1,6 @@
 import Datatable from "@/components/Tables/Datatable";
 import moment from "moment";
 import { Card, CardHeader, CardBody, CardTitle } from "reactstrap";
-import { API_URL } from "@/env";
 
 function Riwayat({ data }) {
 	return (
@@ -20,17 +19,17 @@ function Riwayat({ data }) {
 							</tr>
 						</thead>
 						<tbody>
-							{data && data.length
+							{data.length
 								? data.map((value) => (
 										<tr>
 											<td>{moment(value.createAt).format("DD MMMM YYYY")}</td>
-											<td>{value.description}</td>
+											<td>{value.keterangan}</td>
 											<td>
-												{value.files.map((e) => (
+												{value.dokumen.map((e) => (
 													<>
 														<em className="fa-lg far fa-file-code"></em>
-														<a className="text-muted" href={API_URL + e.path} target="_blank" download={e.name}>
-															{e.name}
+														<a className="text-muted" href={e.path} target="_blank" download={e.judul}>
+															{e.judul}
 														</a>
 													</>
 												))}

+ 31 - 28
components/PT/JawabanBanding/DetailJawaban.js

@@ -4,7 +4,6 @@ import Link from "next/link";
 import { API_URL } from "@/env";
 
 function DetailJawaban({ data }) {
-	const { jawaban } = data.sanksi.banding;
 	return (
 		<>
 			<p className="lead bb">Jawaban Permohonan Banding</p>
@@ -12,38 +11,42 @@ function DetailJawaban({ data }) {
 				<FormGroup>
 					<label md="4">Jawaban:</label>
 					<div md="8">
-						<h3>{jawaban.status}</h3>
-					</div>
-				</FormGroup>
-				<FormGroup>
-					<label md="4">Dokumen Jawaban:</label>
-					<div md="8">
-						<Scrollable height="120px" className="list-group">
-							<table className="table table-bordered bg-transparent">
-								<tbody>
-									{jawaban.files.map((e) => (
-										<tr>
-											<td>
-												<em className="fa-lg far fa-file-code"></em>
-											</td>
-											<td>
-												<a className="text-muted" href={API_URL + e.path} target="_blank" download={e.name}>
-													{e.name}
-												</a>
-											</td>
-										</tr>
-									))}
-								</tbody>
-							</table>
-						</Scrollable>
+						<h3>{data.status}</h3>
 					</div>
 				</FormGroup>
+				{data.dokumen.length ? (
+					<FormGroup>
+						<label md="4">Dokumen Jawaban:</label>
+						<div md="8">
+							<Scrollable height="120px" className="list-group">
+								<table className="table table-bordered bg-transparent">
+									<tbody>
+										{data.dokumen.map((e) => (
+											<tr>
+												<td>
+													<em className="fa-lg far fa-file-code"></em>
+												</td>
+												<td>
+													<a className="text-muted" href={e.path} target="_blank" download={e.judul}>
+														{e.judul}
+													</a>
+												</td>
+											</tr>
+										))}
+									</tbody>
+								</table>
+							</Scrollable>
+						</div>
+					</FormGroup>
+				) : (
+					""
+				)}
 			</form>
-			{jawaban.status === "Ditolak" && (
+			{data.status === "Ditolak" && (
 				<Link
 					href={{
-						pathname: "/app/pt/dokumen-perbaikan/detail",
-						query: { noSanksi: data.sanksi.no_sanksi },
+						pathname: "/pt/dokumen-perbaikan/detail",
+						query: { id: data._id },
 					}}
 				>
 					<Button color="primary">Perbaiki Dokumen</Button>

+ 6 - 7
components/PT/JawabanBanding/TableSanksiJawaban.js

@@ -19,23 +19,22 @@ function TableSanksi({ listData, to, linkName }) {
 						{listData.map((data) => {
 							return (
 								<tr key={data._id}>
-									<td>{data.sanksi.no_sanksi}</td>
+									<td>{data.no_sanksi}</td>
 									<td className="text-nowrap">
 										<div className="media align-items-center">
 											{/* <img className="img-fluid rounded thumb64" src="/static/img/dummy-search.png" alt="Dummy" /> */}
 											<div className="media-body d-flex">
 												<div>
-													<h4 className="m-0">{data.pt.nama}</h4>
-													{/* <small className="text-muted">0742/O/1990 - www.satyagama.ac.id - info@satyagama.ac.id</small> */}
-													<p>{data.sanksi.description.length > 70 ? data.sanksi.description.substring(0, 70) + "..." : data.sanksi.description}</p>
+													<h4 className="m-0">{data.laporan.pt.nama}</h4>
+													<p>{data.keterangan.length > 70 ? dataketerangan.substring(0, 70) + "..." : data.keterangan}</p>
 												</div>
 											</div>
 										</div>
 									</td>
-									<td>{moment(data.sanksi.createdAt).format("DD MMMM YYYY")}</td>
+									<td>{moment(data.createdAt).format("DD MMMM YYYY")}</td>
 									<td>
-										{data.sanksi.banding?.jawaban ? (
-											<Link href={{ pathname: to, query: { noSanksi: data.sanksi.no_sanksi } }}>
+										{data.jawaban?.banding ? (
+											<Link href={{ pathname: to, query: { id: data._id } }}>
 												<Button color="primary">{linkName}</Button>
 											</Link>
 										) : (

+ 5 - 7
components/PT/JawabanKeberatan/DetailJawaban.js

@@ -1,9 +1,7 @@
 import { FormGroup } from "reactstrap";
 import Scrollable from "@/components/Common/Scrollable";
-import { API_URL } from "@/env";
 
 function DetailJawaban({ data }) {
-	const { jawaban } = data.sanksi.keberatan;
 	return (
 		<>
 			<p className="lead bb">Jawaban Permohonan Keberatan</p>
@@ -11,13 +9,13 @@ function DetailJawaban({ data }) {
 				<FormGroup>
 					<label md="4">Jawaban:</label>
 					<div md="8">
-						<h3>{jawaban.status}</h3>
+						<h3>{data.status}</h3>
 					</div>
 				</FormGroup>
 				<FormGroup>
 					<label md="4">Keterangan:</label>
 					<div md="8">
-						<p>{jawaban.description}</p>
+						<p>{data.keterangan}</p>
 					</div>
 				</FormGroup>
 				<FormGroup>
@@ -26,14 +24,14 @@ function DetailJawaban({ data }) {
 						<Scrollable height="120px" className="list-group">
 							<table className="table table-bordered bg-transparent">
 								<tbody>
-									{jawaban.files.map((e) => (
+									{data.dokumen.map((e) => (
 										<tr>
 											<td>
 												<em className="fa-lg far fa-file-code"></em>
 											</td>
 											<td>
-												<a className="text-muted" href={API_URL + e.path} target="_blank" download={e.name}>
-													{e.name}
+												<a className="text-muted" href={e.path} target="_blank" download={e.judul}>
+													{e.judul}
 												</a>
 											</td>
 										</tr>

+ 20 - 16
components/PT/JawabanKeberatan/ModalPermohonan.js

@@ -3,7 +3,6 @@ import Router from "next/router";
 import { Row, Col, FormGroup, Button, Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
 import { addBanding } from "@/actions/banding";
 import { connect } from "react-redux";
-import { notifBanding } from "@/actions/notifikasi";
 import { toast } from "react-toastify";
 
 let Dropzone = null;
@@ -26,6 +25,7 @@ export class ModalPermohonan extends Component {
 		this.state = {
 			modal1: false,
 			files: [],
+			error: null,
 		};
 	}
 
@@ -68,36 +68,40 @@ export class ModalPermohonan extends Component {
 
 	onSubmit = async (e) => {
 		e.preventDefault();
-		const { user, query, data } = this.props;
-		const { noSanksi } = query;
+		const { query, token } = this.props;
+		const { id } = query;
 		const formdata = new FormData();
 		if (this.state.files.length > 0) {
+			this.setState({
+				modal1: !this.state.modal1,
+			});
+
 			this.state.files.forEach((e) => {
-				formdata.append("files", e);
+				formdata.append("dokumen", e);
 			});
 
-			const id = toast.loading("Please wait...");
-			const added = await addBanding({ noSanksi, ptId: user.peran[0].organisasi.id }, formdata);
+			const toastid = toast.loading("Please wait...");
+			const added = await addBanding(token, id, formdata);
 
-			if (added) {
-				toast.update(id, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
-				const notif = await notifBanding({ lembaga: data.sanksi.user.lembaga, pt_name: user.peran[0].organisasi.nama, no_sanksi: data.sanksi.no_sanksi });
+			if (!added) {
+				toast.update(toastid, { render: "All is not good", type: "error", isLoading: false, autoClose: true, closeButton: true });
+			} else {
+				toast.update(toastid, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
 				Router.push({
-					pathname: "/app/pt/jawaban-keberatan",
+					pathname: "/pt/jawaban-keberatan",
 				});
 			}
+		} else {
+			this.setState({ error: "Dokumen harus ada" });
 		}
 	};
 
 	handleKirim = (e) => {
-		this.setState({
-			modal1: !this.state.modal1,
-		});
 		this.onSubmit(e);
 	};
 
 	render() {
-		const { files } = this.state;
+		const { files, error } = this.state;
 
 		const thumbs = files.map((file, index) => (
 			<Col md={3} key={index}>
@@ -141,7 +145,7 @@ export class ModalPermohonan extends Component {
 											);
 										}}
 									</DropzoneWrapper>
-									<span className="form-text">Multiple files upload</span>
+									<span className={`form-text ${error ? "text-danger" : ""}`}>{error ? error : "Multiple files upload"}</span>
 								</div>
 							</FormGroup>
 						</form>
@@ -157,5 +161,5 @@ export class ModalPermohonan extends Component {
 	}
 }
 
-const mapStateToProps = (state) => ({ user: state.user });
+const mapStateToProps = (state) => ({ user: state.user, token: state.token });
 export default connect(mapStateToProps)(ModalPermohonan);

+ 5 - 7
components/PT/JawabanKeberatan/Riwayat.js

@@ -1,10 +1,8 @@
 import Datatable from "@/components/Tables/Datatable";
 import moment from "moment";
 import { Card, CardHeader, CardBody, CardTitle } from "reactstrap";
-import { API_URL } from "@/env";
 
 function Riwayat({ data }) {
-	const { banding } = data.sanksi;
 	return (
 		<Card className="card-default">
 			<CardHeader>
@@ -20,15 +18,15 @@ function Riwayat({ data }) {
 							</tr>
 						</thead>
 						<tbody>
-							{banding ? (
+							{data ? (
 								<tr>
-									<td>{moment(banding.createAt).format("DD MMMM YYYY")}</td>
+									<td>{moment(data.createAt).format("DD MMMM YYYY")}</td>
 									<td>
-										{banding.files.map((e) => (
+										{data.dokumen.map((e) => (
 											<>
 												<em className="fa-lg far fa-file-code"></em>
-												<a className="text-muted" href={API_URL + e.path} target="_blank" download={e.name}>
-													{e.name}
+												<a className="text-muted" href={e.path} target="_blank" download={e.judul}>
+													{e.judul}
 												</a>
 											</>
 										))}

+ 6 - 6
components/PT/JawabanPencabutanSanksi/TableSanksiJawaban.js

@@ -19,21 +19,21 @@ function TableSanksi({ listData, to, linkName }) {
 						{listData.map((data) => {
 							return (
 								<tr key={data._id}>
-									<td>{data.sanksi.no_sanksi}</td>
+									<td>{data.no_sanksi}</td>
 									<td className="text-nowrap">
 										<div className="media align-items-center">
 											<div className="media-body d-flex">
 												<div>
-													<h4 className="m-0">{data.pt.nama}</h4>
-													<p>{data.sanksi.description.length > 70 ? data.sanksi.description.substring(0, 70) + "..." : data.sanksi.description}</p>
+													<h4 className="m-0">{data.laporan.pt.nama}</h4>
+													<p>{data.keterangan.length > 70 ? data.keterangan.substring(0, 70) + "..." : data.keterangan}</p>
 												</div>
 											</div>
 										</div>
 									</td>
-									<td>{moment(data.sanksi.createdAt).format("DD MMMM YYYY")}</td>
+									<td>{moment(data.createdAt).format("DD MMMM YYYY")}</td>
 									<td>
-										{data.sanksi.cabut_sanksi?.jawaban ? (
-											<Link href={{ pathname: to, query: { noSanksi: data.sanksi.no_sanksi } }}>
+										{data.jawaban?.cabut_sanksi ? (
+											<Link href={{ pathname: to, query: { id: data._id } }}>
 												<Button color="primary">{linkName}</Button>
 											</Link>
 										) : (

+ 0 - 1
components/PT/Keberatan/Riwayat.js

@@ -1,7 +1,6 @@
 import Datatable from "@/components/Tables/Datatable";
 import moment from "moment";
 import { Card, CardHeader, CardBody, CardTitle } from "reactstrap";
-import { API_URL } from "@/env";
 
 function Riwayat({ data }) {
 	return (

+ 3 - 1
components/Pemeriksaan/InputEvaluasi.js

@@ -93,7 +93,7 @@ export default class InputEvaluasi extends Component {
 		});
 	};
 
-	onSubmit = async (data) => {
+	onSubmit = async (data, { resetForm }) => {
 		const { token, query } = this.props;
 		const { id } = query;
 		const formdata = new FormData();
@@ -108,6 +108,8 @@ export default class InputEvaluasi extends Component {
 			success: "Success",
 			error: "Error",
 		});
+		this.setState({ files: [] });
+		resetForm();
 	};
 
 	render() {

+ 67 - 0
components/Pemeriksaan/TableLaporan.js

@@ -0,0 +1,67 @@
+import Datatable from "@/components/Tables/Datatable";
+import { Button } from "reactstrap";
+import Link from "next/link";
+import moment from "moment";
+
+function TableLaporan({ listData, to, linkName }) {
+	return (
+		<div className="card b">
+			<div className="card-body">
+				{listData && (
+					<Datatable options={{ responsive: false }}>
+						<table className="table w-100">
+							<thead>
+								<tr>
+									<th>No.Laporan</th>
+									<th>Deskripsi Laporan</th>
+									<th>Status</th>
+									<th>Created</th>
+									<th></th>
+								</tr>
+							</thead>
+							<tbody>
+								{listData.map((data) => {
+									return (
+										<tr key={data._id}>
+											<td>{data.no_laporan}</td>
+											<td className="text-nowrap">
+												<div className="media align-items-center">
+													<div className="media-body d-flex">
+														<div>
+															<h4 className="m-0">{data.pt.nama}</h4>
+															<p>{data.keterangan.length > 35 ? data.keterangan.substring(0, 35) + "..." : data.keterangan}</p>
+														</div>
+													</div>
+												</div>
+											</td>
+
+											<td>{data.evaluasi?.length ? <div className="badge badge-info">Sudah diperiksa</div> : <div className="badge badge-danger">Belum dperiksa</div>}</td>
+
+											<td>{moment(data.createdAt).fromNow()}</td>
+											<td>
+												<div className="ml-auto">
+													<Link
+														href={{
+															pathname: to,
+															query: { id: data._id },
+														}}
+													>
+														<Button color="primary" size="sm">
+															{linkName}
+														</Button>
+													</Link>
+												</div>
+											</td>
+										</tr>
+									);
+								})}
+							</tbody>
+						</table>
+					</Datatable>
+				)}
+			</div>
+		</div>
+	);
+}
+
+export default TableLaporan;

+ 7 - 8
components/PencabutanSanksi/Riwayat.js

@@ -4,7 +4,6 @@ import { Card, CardHeader, CardBody, CardTitle } from "reactstrap";
 import { API_URL } from "@/env";
 
 function Riwayat({ data }) {
-	const { jawaban } = data.sanksi.cabut_sanksi;
 	return (
 		<Card className="card-default">
 			<CardHeader>
@@ -22,17 +21,17 @@ function Riwayat({ data }) {
 							</tr>
 						</thead>
 						<tbody>
-							{jawaban ? (
+							{data ? (
 								<tr>
-									<td>{moment(jawaban.createAt).format("DD MMMM YYYY")}</td>
-									<td>{jawaban.status}</td>
-									<td>{jawaban.description}</td>
+									<td>{moment(data.createAt).format("DD MMMM YYYY")}</td>
+									<td>{data.status}</td>
+									<td>{data.keterangan}</td>
 									<td>
-										{jawaban.files.map((e) => (
+										{data.dokumen.map((e) => (
 											<>
 												<em className="fa-lg far fa-file-code"></em>
-												<a className="text-muted" href={API_URL + e.path} target="_blank" download={e.name}>
-													{e.name}
+												<a className="text-muted" href={e.path} target="_blank" download={e.judul}>
+													{e.judul}
 												</a>
 											</>
 										))}

+ 6 - 6
components/PencabutanSanksi/TableSanksi.js

@@ -23,25 +23,25 @@ function TableSanksi({ listData, to, linkName }) {
 								? listData.map((data) => {
 										return (
 											<tr key={data._id}>
-												<td>{data.sanksi.no_sanksi}</td>
+												<td>{data.no_sanksi}</td>
 												<td>
 													<div className="media align-items-center">
 														<div className="media-body d-flex">
 															<div>
-																<h4 className="m-0">{data.pt.nama}</h4>
-																<p>{data.description.length > 25 ? data.description.substring(0, 25) + "..." : data.description}</p>
+																<h4 className="m-0">{data.laporan.pt.nama}</h4>
+																<p>{data.keterangan.length > 25 ? data.keterangan.substring(0, 25) + "..." : data.keterangan}</p>
 															</div>
 														</div>
 													</div>
 												</td>
-												<td>{moment(data.sanksi.createdAt).fromNow()}</td>
-												<td>{data.sanksi.cabut_sanksi.jawaban ? <div className="badge badge-info">Sudah Dijawab</div> : <div className="badge badge-danger">Belum Dijawab</div>}</td>
+												<td>{moment(data.createdAt).fromNow()}</td>
+												<td>{data.jawaban.cabut_sanksi ? <div className="badge badge-info">Sudah Dijawab</div> : <div className="badge badge-danger">Belum Dijawab</div>}</td>
 												<td>
 													<div className="ml-auto">
 														<Link
 															href={{
 																pathname: to,
-																query: { noSanksi: data.sanksi.no_sanksi, ptId: data.pt_id },
+																query: { id: data._id },
 															}}
 														>
 															<Button color="primary" size="sm">

+ 67 - 0
components/Penjadwalan/TableLaporan.js

@@ -0,0 +1,67 @@
+import Datatable from "@/components/Tables/Datatable";
+import { Button } from "reactstrap";
+import Link from "next/link";
+import moment from "moment";
+
+function TableLaporan({ listData, to, linkName }) {
+	return (
+		<div className="card b">
+			<div className="card-body">
+				{listData && (
+					<Datatable options={{ responsive: false }}>
+						<table className="table w-100">
+							<thead>
+								<tr>
+									<th>No.Laporan</th>
+									<th>Deskripsi Laporan</th>
+									<th>Status</th>
+									<th>Created</th>
+									<th></th>
+								</tr>
+							</thead>
+							<tbody>
+								{listData.map((data) => {
+									return (
+										<tr key={data._id}>
+											<td>{data.no_laporan}</td>
+											<td className="text-nowrap">
+												<div className="media align-items-center">
+													<div className="media-body d-flex">
+														<div>
+															<h4 className="m-0">{data.pt.nama}</h4>
+															<p>{data.keterangan.length > 35 ? data.keterangan.substring(0, 35) + "..." : data.keterangan}</p>
+														</div>
+													</div>
+												</div>
+											</td>
+
+											<td>{data.jadwal ? <div className="badge badge-info">Ada Jadwal</div> : <div className="badge badge-danger">Tidak ada jadwal</div>}</td>
+
+											<td>{moment(data.createdAt).fromNow()}</td>
+											<td>
+												<div className="ml-auto">
+													<Link
+														href={{
+															pathname: to,
+															query: { id: data._id },
+														}}
+													>
+														<Button color="primary" size="sm">
+															{linkName}
+														</Button>
+													</Link>
+												</div>
+											</td>
+										</tr>
+									);
+								})}
+							</tbody>
+						</table>
+					</Datatable>
+				)}
+			</div>
+		</div>
+	);
+}
+
+export default TableLaporan;

+ 2 - 2
components/Sanksi/TableLaporan.js

@@ -12,7 +12,7 @@ function TableLaporan({ listData }) {
 						<table className="table w-100">
 							<thead>
 								<tr>
-									<th>#ID</th>
+									<th>No.Laporan</th>
 									<th>Deskripsi Laporan</th>
 									<th>Status</th>
 									<th>Created</th>
@@ -35,7 +35,7 @@ function TableLaporan({ listData }) {
 												</div>
 											</td>
 											<td>
-												<div className="badge badge-info">{data.role_data}</div>
+												<td>{data.sanksi ? <div className="badge badge-info">Sudah ditetapkan</div> : <div className="badge badge-danger">Belum ditetapkan</div>}</td>
 											</td>
 											<td>{moment(data.createdAt).fromNow()}</td>
 											<td>

+ 8 - 0
package-lock.json

@@ -7059,6 +7059,14 @@
 			"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
 			"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
 		},
+		"moment-timezone": {
+			"version": "0.5.34",
+			"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.34.tgz",
+			"integrity": "sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==",
+			"requires": {
+				"moment": ">= 2.9.0"
+			}
+		},
 		"morris.js.so": {
 			"version": "0.5.1",
 			"resolved": "https://registry.npmjs.org/morris.js.so/-/morris.js.so-0.5.1.tgz",

+ 1 - 0
package.json

@@ -66,6 +66,7 @@
 		"loaders.css": "0.1.2",
 		"matchmedia": "0.1.2",
 		"moment": "^2.29.1",
+		"moment-timezone": "^0.5.34",
 		"morris.js.so": "0.5.1",
 		"nestable": "themicon/nestable",
 		"next": "9.5.5",

+ 119 - 78
pages/app/banding/detail.js

@@ -7,13 +7,16 @@ import Header from "@/components/Main/Header";
 import DetailPT from "@/components/Main/DetailPT";
 import PermohonanPT from "@/components/Main/PermohonanPT";
 import Riwayat from "@/components/Banding/Riwayat";
-import { getSanksi } from "@/actions/sanksi";
+import { getOneSanksi } from "@/actions/sanksi";
 import { addJawabanBanding } from "@/actions/banding";
 import ContentWrapper from "@/components/Layout/ContentWrapper";
 import { Row, Col, Card, CardBody, FormGroup, Button, Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
 import { getPT } from "@/actions/PT";
 import Loader from "@/components/Common/Loader";
 import { toast } from "react-toastify";
+import { connect } from "react-redux";
+import { Formik, Form, Field, ErrorMessage } from "formik";
+import * as Yup from "yup";
 
 let Dropzone = null;
 class DropzoneWrapper extends Component {
@@ -30,7 +33,10 @@ class DropzoneWrapper extends Component {
 }
 
 const selectInstanceId = 1;
-
+const jawabanBandingSchema = Yup.object().shape({
+	status: Yup.string().required("Harap Diisi"),
+	dokumen: Yup.array().notRequired(),
+});
 class JawabanBanding extends Component {
 	constructor(props) {
 		super(props);
@@ -39,7 +45,7 @@ class JawabanBanding extends Component {
 			selectedOption: null,
 			files: [],
 			sanksi: {},
-			pt: {},
+			pt: null,
 		};
 	}
 
@@ -48,10 +54,10 @@ class JawabanBanding extends Component {
 	};
 
 	componentDidMount = async () => {
-		const { query } = this.props;
-		const sanksi = await getSanksi(query);
-		const pt = await getPT({ id: query.ptId });
-		this.setState({ pt, sanksi });
+		const { query, token } = this.props;
+		const sanksi = await getOneSanksi(token, query.id, { banding: true });
+		const pt = sanksi.data.laporan.pt;
+		this.setState({ sanksi, pt });
 	};
 
 	toggleModal = () => {
@@ -94,22 +100,24 @@ class JawabanBanding extends Component {
 		});
 	};
 
-	handelSimpan = async (e) => {
-		e.preventDefault();
-		const { selectedOption } = this.state;
-		const { noSanksi, ptId } = this.props.query;
-		const formdata = new FormData();
-		formdata.append("status", selectedOption.value);
-		if (this.state.files.length > 0) {
-			this.state.files.forEach((e) => {
-				formdata.append("files", e);
-			});
+	handelSimpan = async () => {
+		if (this.state.modal === true) {
+			this.toggleModal();
 		}
-
-		const id = toast.loading("Please wait...");
-		const added = await addJawabanBanding({ noSanksi, ptId }, formdata);
-		if (added) {
-			toast.update(id, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
+		const { data } = this.state;
+		const { query, token } = this.props;
+		const { id } = query;
+		const formdata = new FormData();
+		formdata.append("status", data.status);
+		data.dokumen.forEach((e) => {
+			formdata.append("dokumen", e);
+		});
+		const toastid = toast.loading("Please wait...");
+		const added = await addJawabanBanding(token, id, formdata);
+		if (!added) {
+			toast.update(toastid, { render: "All is not good", type: "error", isLoading: false, autoClose: true, closeButton: true });
+		} else {
+			toast.update(toastid, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
 			Router.push({
 				pathname: "/app/banding",
 			});
@@ -138,64 +146,96 @@ class JawabanBanding extends Component {
 						</div>
 					</div>
 					<Row>
-						{sanksi.data && sanksi.data.length ? (
+						{sanksi.data ? (
 							<Col xl={9}>
 								<Card className="card-default">
 									<CardBody>
 										<Row>
 											<Col lg={12}>
-												<DetailSanksi data={sanksi.data[0]} />
-												<PermohonanPT data={sanksi.data[0].sanksi.banding} title="Permohonan Banding" />
+												<DetailSanksi data={sanksi.data} />
+												<PermohonanPT data={sanksi.data.pengajuan.banding} title="Permohonan Banding" />
 												<p className="lead bb">Jawaban</p>
-												<form className="form-horizontal" method="get" action="/" onSubmit={this.onSubmit}>
-													<FormGroup>
-														<label className="row-form-label">Status:</label>
-														<div className="row-md-10">
-															<Select
-																instanceId={selectInstanceId + 1}
-																value={this.state.selectedOption}
-																onChange={this.handleChangeSelect}
-																options={[
-																	{ value: "Ditolak", label: "Ditolak", className: "State-ACT" },
-																	{ value: "Dikabulkan", label: "Dikabulkan", className: "State-ACT" },
-																]}
-																required
-															/>
-															{/* <span className="form-text">Pilih Jenis Pelanggaran</span> */}
-														</div>
-													</FormGroup>
-													<FormGroup>
-														<label className="row-form-label">Dokumen Jawaban:</label>
-														<div className="row-md-10">
-															<DropzoneWrapper className="" onDrop={this.onDrop}>
-																{({ getRootProps, getInputProps, isDragActive }) => {
-																	return (
-																		<div {...getRootProps()} className={"dropzone card p-3 " + (isDragActive ? "dropzone-drag-active" : "")}>
-																			<input {...getInputProps()} />
-																			<div className="dropzone-previews flex">
-																				{this.state.files.length > 0 ? <Row>{thumbs}</Row> : <div className="text-center dz-default dz-message">Drop files here to upload</div>}
-																			</div>
-																			<div className="d-flex align-items-center">
-																				<small className="ml-auto">
-																					<button type="button" className="btn btn-link" onClick={this.clearFiles}>
-																						Clear files
-																					</button>
-																				</small>
-																			</div>
-																		</div>
-																	);
-																}}
-															</DropzoneWrapper>
-														</div>
-													</FormGroup>
-													<FormGroup>
-														<div className="row-xl-10">
-															<Button color="primary" onClick={sanksi.data && sanksi.data.length && sanksi.data[0].sanksi.banding.jawaban ? this.toggleModal : this.handelSimpan}>
-																Simpan
-															</Button>
-														</div>
-													</FormGroup>
-												</form>
+												<Formik
+													initialValues={{
+														status: "",
+														dokumen: [],
+													}}
+													validationSchema={jawabanBandingSchema}
+													onSubmit={async (data) => {
+														this.setState({ data });
+														if (sanksi.data.jawaban?.banding) this.toggleModal();
+														else await this.handelSimpan();
+													}}
+												>
+													{() => (
+														<Form className="form-horizontal">
+															<FormGroup>
+																<label className="row-form-label">Status:</label>
+																<div className="row-md-10">
+																	<Field name="status">
+																		{({ field, form, meta }) => (
+																			<Select
+																				instanceId={selectInstanceId + 1}
+																				value={this.state.selectedOption}
+																				onChange={(e) => {
+																					this.handleChangeSelect(e);
+																					form.setFieldValue(field.name, e.value);
+																				}}
+																				options={[
+																					{ value: "Ditolak", label: "Ditolak", className: "State-ACT" },
+																					{ value: "Dikabulkan", label: "Dikabulkan", className: "State-ACT" },
+																				]}
+																			/>
+																		)}
+																	</Field>
+																	<ErrorMessage name="status" component="div" className="form-text text-danger" />
+																</div>
+															</FormGroup>
+															<FormGroup>
+																<label className="row-form-label">Dokumen Jawaban:</label>
+																<div className="row-md-10">
+																	<Field name="dokumen">
+																		{({ field, form }) => (
+																			<DropzoneWrapper
+																				className=""
+																				onDrop={(e) => {
+																					this.onDrop(e);
+																					form.setFieldValue(field.name, e);
+																				}}
+																			>
+																				{({ getRootProps, getInputProps, isDragActive }) => {
+																					return (
+																						<div {...getRootProps()} className={"dropzone card p-3 " + (isDragActive ? "dropzone-drag-active" : "")}>
+																							<input {...getInputProps()} />
+																							<div className="dropzone-previews flex">
+																								{this.state.files.length > 0 ? <Row>{thumbs}</Row> : <div className="text-center dz-default dz-message">Drop files here to upload</div>}
+																							</div>
+																							<div className="d-flex align-items-center">
+																								<small className="ml-auto">
+																									<button type="button" className="btn btn-link" onClick={this.clearFiles}>
+																										Clear files
+																									</button>
+																								</small>
+																							</div>
+																						</div>
+																					);
+																				}}
+																			</DropzoneWrapper>
+																		)}
+																	</Field>
+																	<ErrorMessage name="dokumen" component="div" className="form-text text-danger" />
+																</div>
+															</FormGroup>
+															<FormGroup row>
+																<div className="col-xl-10">
+																	<Button color="primary" type="submit">
+																		Simpan
+																	</Button>
+																</div>
+															</FormGroup>
+														</Form>
+													)}
+												</Formik>
 											</Col>
 										</Row>
 									</CardBody>
@@ -204,12 +244,12 @@ class JawabanBanding extends Component {
 						) : (
 							<Loader />
 						)}
-						<Col xl={3}>{pt?.data ? <DetailPT data={pt.data[0]} /> : <Loader />}</Col>
+						<Col xl={3}>{pt ? <DetailPT data={pt} /> : <Loader />}</Col>
 					</Row>
-					{sanksi.data && sanksi.data.length && (
+					{sanksi.data && (
 						<Row>
 							<Col>
-								<Riwayat data={sanksi.data[0].sanksi.banding.jawaban} />
+								<Riwayat data={sanksi.data.jawaban.banding} />
 							</Col>
 						</Row>
 					)}
@@ -230,4 +270,5 @@ class JawabanBanding extends Component {
 	}
 }
 
-export default JawabanBanding;
+const mapStateToProps = (state) => ({ user: state.user, token: state.token });
+export default connect(mapStateToProps)(JawabanBanding);

+ 6 - 3
pages/app/banding/index.js

@@ -5,6 +5,7 @@ import CaseProgress from "@/components/Main/CaseProgress";
 import TableSanksi from "@/components/Banding/TableSanksi";
 import { getSanksi } from "@/actions/sanksi";
 import Loader from "@/components/Common/Loader";
+import { connect } from "react-redux";
 
 class Banding extends Component {
 	constructor(props) {
@@ -15,7 +16,8 @@ class Banding extends Component {
 	}
 
 	componentDidMount = async () => {
-		const sanksi = await getSanksi({ banding: true });
+		const { token } = this.props;
+		const sanksi = await getSanksi(token, { banding: true });
 		this.setState({ sanksi });
 	};
 
@@ -28,11 +30,12 @@ class Banding extends Component {
 					<Col lg="4">
 						<CaseProgress />
 					</Col>
-					<Col lg="8">{sanksi?.data ? <TableSanksi listData={sanksi.data} to="/app/banding/detail" linkName="Detail" /> : <Loader />}</Col>
+					<Col lg="8">{sanksi.data ? <TableSanksi listData={sanksi.data} to="/app/banding/detail" linkName="Detail" /> : <Loader />}</Col>
 				</Row>
 			</ContentWrapper>
 		);
 	}
 }
 
-export default Banding;
+const mapStateToProps = (state) => ({ user: state.user, token: state.token });
+export default connect(mapStateToProps)(Banding);

+ 4 - 4
pages/app/keberatan/detail.js

@@ -104,7 +104,9 @@ class DetailKeberatan extends Component {
 	};
 
 	handelSimpan = async () => {
-		this.toggleModal();
+		if (this.state.modal === true) {
+			this.toggleModal();
+		}
 		const { data } = this.state;
 		const { query, token } = this.props;
 		const { id } = query;
@@ -173,7 +175,6 @@ class DetailKeberatan extends Component {
 													}}
 													validationSchema={jawabanKeberatanSchema}
 													onSubmit={async (data) => {
-														const { sanksi } = this.state;
 														this.setState({ data });
 														if (sanksi.data.jawaban?.keberatan) this.toggleModal();
 														else await this.handelSimpan();
@@ -198,7 +199,6 @@ class DetailKeberatan extends Component {
 																					{ value: "Mengubah Keputusan", label: "Mengubah Keputusan", className: "State-ACT" },
 																					{ value: "Membatalkan Keputusan", label: "Membatalkan Keputusan", className: "State-ACT" },
 																				]}
-																				required
 																			/>
 																		)}
 																	</Field>
@@ -208,7 +208,7 @@ class DetailKeberatan extends Component {
 															<FormGroup>
 																<label className="row-form-label">Keterangan Jawaban:</label>
 																<div className="row-md-10">
-																	<Field name="keterangan">{({ field }) => <Input type="textarea" {...field} required />}</Field>
+																	<Field name="keterangan">{({ field }) => <Input type="textarea" {...field} />}</Field>
 																	<ErrorMessage name="keterangan" component="div" className="form-text text-danger" />
 																	{/* <span className="form-text">Deskripsi pelaporan minimum karakter 50 maksimum 200 karakter</span> */}
 																</div>

+ 14 - 14
pages/app/pemantauan-perbaikan/detail.js

@@ -4,30 +4,29 @@ import Link from "next/link";
 import Header from "@/components/Main/Header";
 import DetailPT from "@/components/Main/DetailPT";
 import Riwayat from "@/components/DocPerbaikan/Riwayat";
-import { getSanksi } from "@/actions/sanksi";
+import { getOneSanksi } from "@/actions/sanksi";
 import ContentWrapper from "@/components/Layout/ContentWrapper";
 import { Row, Col, Card, CardBody } from "reactstrap";
 import { getPT } from "@/actions/PT";
 import Loader from "@/components/Common/Loader";
+import { connect } from "react-redux";
 
 class PemantauanDokumen extends Component {
 	constructor(props) {
 		super(props);
 		this.state = {
 			sanksi: {},
-			pt: {},
+			pt: null,
 		};
 	}
 
-	static getInitialProps = async ({ query }) => {
-		return { query };
-	};
+	static getInitialProps = async ({ query }) => ({ query });
 
 	componentDidMount = async () => {
-		const { query } = this.props;
-		const sanksi = await getSanksi(query);
-		const pt = await getPT({ id: query.ptId });
-		this.setState({ pt, sanksi });
+		const { query, token } = this.props;
+		const sanksi = await getOneSanksi(token, query.id);
+		const pt = sanksi.data.laporan.pt;
+		this.setState({ sanksi, pt });
 	};
 
 	render() {
@@ -45,13 +44,13 @@ class PemantauanDokumen extends Component {
 						</div>
 					</div>
 					<Row>
-						{sanksi.data && sanksi.data.length ? (
+						{sanksi.data ? (
 							<Col xl="9">
 								<Card className="card-default">
 									<CardBody>
 										<Row>
 											<Col lg={12}>
-												<DetailSanksi data={sanksi.data[0]} />
+												<DetailSanksi data={sanksi.data} />
 											</Col>
 										</Row>
 									</CardBody>
@@ -60,10 +59,10 @@ class PemantauanDokumen extends Component {
 						) : (
 							<Loader />
 						)}
-						<Col xl="3">{pt?.data ? <DetailPT data={pt.data[0]} /> : <Loader />}</Col>
+						<Col xl="3">{pt ? <DetailPT data={pt} /> : <Loader />}</Col>
 					</Row>
 					<Row>
-						<Col>{sanksi.data && sanksi.data.length && <Riwayat data={sanksi.data[0].sanksi.doc_perbaikan} />}</Col>
+						<Col>{sanksi.data && <Riwayat data={sanksi.data.perbaikan} />}</Col>
 					</Row>
 				</div>
 			</ContentWrapper>
@@ -71,4 +70,5 @@ class PemantauanDokumen extends Component {
 	}
 }
 
-export default PemantauanDokumen;
+const mapStateToProps = (state) => ({ user: state.user, token: state.token });
+export default connect(mapStateToProps)(PemantauanDokumen);

+ 4 - 6
pages/app/pemantauan-perbaikan/index.js

@@ -16,10 +16,8 @@ class PemantauanPerbaikan extends Component {
 	}
 
 	componentDidMount = async () => {
-		const { organisasi, peran } = this.props.user.peran[0];
-		const query = { role: peran.id === 2021 ? "lldikti" : "dikti", docPerbaikan: true };
-		if (peran.id === 2021) query.orgId = organisasi.id;
-		const sanksi = await getSanksi(query);
+		const { token } = this.props;
+		const sanksi = await getSanksi(token, { perbaikan: true });
 		this.setState({ sanksi });
 	};
 
@@ -32,12 +30,12 @@ class PemantauanPerbaikan extends Component {
 					<Col lg="4">
 						<CaseProgress />
 					</Col>
-					<Col lg="8">{sanksi?.data ? <TableSanksi listData={sanksi.data} to="/app/pemantauan-perbaikan/detail" linkName="Detail" /> : <Loader />}</Col>
+					<Col lg="8">{sanksi.data ? <TableSanksi listData={sanksi.data} to="/app/pemantauan-perbaikan/detail" linkName="Detail" /> : <Loader />}</Col>
 				</Row>
 			</ContentWrapper>
 		);
 	}
 }
 
-const mapStateToProps = (state) => ({ user: state.user });
+const mapStateToProps = (state) => ({ user: state.user, token: state.token });
 export default connect(mapStateToProps)(PemantauanPerbaikan);

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

@@ -3,7 +3,7 @@ import ContentWrapper from "@/components/Layout/ContentWrapper";
 import { Row, Col } from "reactstrap";
 import { getPelaporan } from "@/actions/pelaporan";
 import CaseProgress from "@/components/Main/CaseProgress";
-import TableLaporan from "@/components/Main/TableLaporan";
+import TableLaporan from "@/components/Pemeriksaan/TableLaporan";
 import { connect } from "react-redux";
 import Loader from "@/components/Common/Loader";
 

+ 134 - 91
pages/app/pencabutan-sanksi/detail.js

@@ -7,13 +7,22 @@ import Header from "@/components/Main/Header";
 import DetailPT from "@/components/Main/DetailPT";
 import PermohonanPT from "@/components/Main/PermohonanPT";
 import Riwayat from "@/components/PencabutanSanksi/Riwayat";
-import { getSanksi } from "@/actions/sanksi";
+import { getOneSanksi } from "@/actions/sanksi";
 import { addJawabanCabutSanksi } from "@/actions/cabutSanksi";
 import ContentWrapper from "@/components/Layout/ContentWrapper";
 import { Row, Col, Card, CardBody, FormGroup, Button, Input, Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
 import { getPT } from "@/actions/PT";
 import Loader from "@/components/Common/Loader";
 import { toast } from "react-toastify";
+import { connect } from "react-redux";
+import { Formik, Form, Field, ErrorMessage } from "formik";
+import * as Yup from "yup";
+
+const jawabanCabutSanksiSchema = Yup.object().shape({
+	status: Yup.string().required("Harap Diisi"),
+	keterangan: Yup.string().max(200).notRequired(),
+	dokumen: Yup.array().notRequired(),
+});
 
 let Dropzone = null;
 class DropzoneWrapper extends Component {
@@ -39,19 +48,18 @@ class JawabanPencabutanSanksi extends Component {
 			files: [],
 			keterangan: "",
 			sanksi: {},
-			pt: {},
+			pt: null,
+			data: {},
 		};
 	}
 
-	static getInitialProps = async ({ query }) => {
-		return { query };
-	};
+	static getInitialProps = async ({ query }) => ({ query });
 
 	componentDidMount = async () => {
-		const { query } = this.props;
-		const sanksi = await getSanksi(query);
-		const pt = await getPT({ id: query.ptId });
-		this.setState({ pt, sanksi });
+		const { query, token } = this.props;
+		const sanksi = await getOneSanksi(token, query.id);
+		const pt = sanksi.data.laporan.pt;
+		this.setState({ sanksi, pt });
 	};
 
 	toggleModal = () => {
@@ -98,26 +106,25 @@ class JawabanPencabutanSanksi extends Component {
 		this.setState({ keterangan: e.target.value });
 	};
 
-	handleSimpan = async (e) => {
-		e.preventDefault();
-		const { selectedOption, keterangan } = this.state;
-		const { noSanksi, ptId } = this.props.query;
+	handleSimpan = async () => {
+		const { data } = this.state;
+		console.log(data);
+		const { token, query } = this.props;
 		const formdata = new FormData();
-		formdata.append("status", selectedOption.value);
-		formdata.append("description", keterangan);
-		if (this.state.files.length > 0) {
-			this.state.files.forEach((e) => {
-				formdata.append("files", e);
+		formdata.append("status", data.status);
+		formdata.append("keterangan", data.keterangan);
+		this.state.files.forEach((e) => {
+			formdata.append("dokumen", e);
+		});
+		const toastid = toast.loading("Please wait...");
+		const added = await addJawabanCabutSanksi(token, query.id, formdata);
+		if (!added) {
+			toast.update(toastid, { render: "All is not good", type: "error", isLoading: false, autoClose: true, closeButton: true });
+		} else {
+			toast.update(toastid, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
+			Router.push({
+				pathname: "/app/pencabutan-sanksi",
 			});
-			const id = toast.loading("Please wait...");
-			const added = await addJawabanCabutSanksi({ noSanksi, ptId }, formdata);
-			// console.log(added);
-			if (added) {
-				toast.update(id, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
-				Router.push({
-					pathname: "/app/pencabutan-sanksi",
-				});
-			}
 		}
 	};
 
@@ -149,69 +156,104 @@ class JawabanPencabutanSanksi extends Component {
 									<CardBody>
 										<Row>
 											<Col lg={12}>
-												<DetailSanksi data={sanksi.data[0]} />
-												<PermohonanPT data={sanksi.data[0].sanksi.cabut_sanksi} />
+												<DetailSanksi data={sanksi.data} />
+												<PermohonanPT data={sanksi.data.pengajuan.cabut_sanksi} />
 												<p className="lead bb">Jawaban</p>
-												<form className="form-horizontal" method="get" action="/" onSubmit={this.onSubmit}>
-													<FormGroup>
-														<label className="row-form-label">Status:</label>
-														<div className="row-md-10">
-															<Select
-																instanceId={selectInstanceId + 1}
-																value={this.state.selectedOption}
-																onChange={this.handleChangeSelect}
-																options={[
-																	{ value: "Diterima", label: "Diterima", className: "State-ACT" },
-																	{ value: "Rekomendasi Perbaikan", label: "Rekomendasi Perbaikan", className: "State-ACT" },
-																]}
-																required
-															/>
-															{/* <span className="form-text">Pilih Jenis Pelanggaran</span> */}
-														</div>
-													</FormGroup>
-													{selectedOption && selectedOption.value === "Rekomendasi Perbaikan" ? (
-														<FormGroup>
-															<label className="row-form-label">Keterangan:</label>
-															<div className="row-md-10">
-																<Input type="textarea" value={this.state.keterangan} onChange={this.setKeterangan} required />
-																{/* <span className="form-text">Deskripsi pelaporan minimum karakter 50 maksimum 200 karakter</span> */}
-															</div>
-														</FormGroup>
-													) : (
-														""
+												<Formik
+													initialValues={{
+														status: "",
+														keterangan: "",
+														dokumen: [],
+													}}
+													validationSchema={jawabanCabutSanksiSchema}
+													onSubmit={async (data) => {
+														this.setState({ data });
+														if (sanksi.data.jawaban?.cabut_sanksi) this.toggleModal();
+														else await this.handleSimpan();
+													}}
+												>
+													{() => (
+														<Form className="form-horizontal">
+															<FormGroup>
+																<label className="row-form-label">Status:</label>
+																<div className="row-md-10">
+																	<Field name="status">
+																		{({ field, form }) => (
+																			<Select
+																				instanceId={selectInstanceId + 1}
+																				value={this.state.selectedOption}
+																				onChange={(e) => {
+																					this.handleChangeSelect(e);
+																					form.setFieldValue(field.name, e.value);
+																				}}
+																				options={[
+																					{ value: "Diterima", label: "Diterima", className: "State-ACT" },
+																					{ value: "Rekomendasi Perbaikan", label: "Rekomendasi Perbaikan", className: "State-ACT" },
+																				]}
+																			/>
+																		)}
+																	</Field>
+																	<ErrorMessage name="status" component="div" className="form-text text-danger" />
+																	{/* <span className="form-text">Pilih Jenis Pelanggaran</span> */}
+																</div>
+															</FormGroup>
+															{selectedOption && selectedOption.value === "Rekomendasi Perbaikan" ? (
+																<FormGroup>
+																	<label className="row-form-label">Keterangan:</label>
+																	<div className="row-md-10">
+																		<Field name="keterangan">{({ field }) => <Input type="textarea" {...field} />}</Field>
+																		<ErrorMessage name="keterangan" component="div" className="form-text text-danger" />
+																		{/* <span className="form-text">Deskripsi pelaporan minimum karakter 50 maksimum 200 karakter</span> */}
+																	</div>
+																</FormGroup>
+															) : (
+																""
+															)}
+															<FormGroup>
+																<label className="row-form-label">Upload Dokumen:</label>
+																<div className="row-md-10">
+																	<Field name="dokumen">
+																		{({ field, form }) => (
+																			<DropzoneWrapper
+																				className=""
+																				onDrop={(e) => {
+																					this.onDrop(e);
+																					form.setFieldValue(field.name, e);
+																				}}
+																			>
+																				{({ getRootProps, getInputProps, isDragActive }) => {
+																					return (
+																						<div {...getRootProps()} className={"dropzone card p-3 " + (isDragActive ? "dropzone-drag-active" : "")}>
+																							<input {...getInputProps()} />
+																							<div className="dropzone-previews flex">
+																								{this.state.files.length > 0 ? <Row>{thumbs}</Row> : <div className="text-center dz-default dz-message">Drop files here to upload</div>}
+																							</div>
+																							<div className="d-flex align-items-center">
+																								<small className="ml-auto">
+																									<button type="button" className="btn btn-link" onClick={this.clearFiles}>
+																										Clear files
+																									</button>
+																								</small>
+																							</div>
+																						</div>
+																					);
+																				}}
+																			</DropzoneWrapper>
+																		)}
+																	</Field>
+																	<ErrorMessage name="dokumen" component="div" className="form-text text-danger" />
+																</div>
+															</FormGroup>
+															<FormGroup>
+																<div className="row-xl-10">
+																	<Button color="primary" type="submit">
+																		Simpan
+																	</Button>
+																</div>
+															</FormGroup>
+														</Form>
 													)}
-													<FormGroup>
-														<label className="row-form-label">Upload Dokumen:</label>
-														<div className="row-md-10">
-															<DropzoneWrapper className="" onDrop={this.onDrop}>
-																{({ getRootProps, getInputProps, isDragActive }) => {
-																	return (
-																		<div {...getRootProps()} className={"dropzone card p-3 " + (isDragActive ? "dropzone-drag-active" : "")}>
-																			<input {...getInputProps()} />
-																			<div className="dropzone-previews flex">
-																				{this.state.files.length > 0 ? <Row>{thumbs}</Row> : <div className="text-center dz-default dz-message">Drop files here to upload</div>}
-																			</div>
-																			<div className="d-flex align-items-center">
-																				<small className="ml-auto">
-																					<button type="button" className="btn btn-link" onClick={this.clearFiles}>
-																						Clear files
-																					</button>
-																				</small>
-																			</div>
-																		</div>
-																	);
-																}}
-															</DropzoneWrapper>
-														</div>
-													</FormGroup>
-													<FormGroup>
-														<div className="row-xl-10">
-															<Button color="primary" onClick={sanksi.data && sanksi.data.length && sanksi.data[0].sanksi.cabut_sanksi.jawaban ? this.toggleModal : this.handleSimpan}>
-																Simpan
-															</Button>
-														</div>
-													</FormGroup>
-												</form>
+												</Formik>
 											</Col>
 										</Row>
 									</CardBody>
@@ -220,12 +262,12 @@ class JawabanPencabutanSanksi extends Component {
 						) : (
 							<Loader />
 						)}
-						<Col xl="3">{pt.data ? <DetailPT data={pt.data[0]} /> : <Loader />}</Col>
+						<Col xl="3">{pt ? <DetailPT data={pt} /> : <Loader />}</Col>
 					</Row>
 					{sanksi.data && (
 						<Row>
 							<Col>
-								<Riwayat data={sanksi.data[0]} />
+								<Riwayat data={sanksi.data.jawaban.cabut_sanksi} />
 							</Col>
 						</Row>
 					)}
@@ -246,4 +288,5 @@ class JawabanPencabutanSanksi extends Component {
 	}
 }
 
-export default JawabanPencabutanSanksi;
+const mapStateToProps = (state) => ({ user: state.user, token: state.token });
+export default connect(mapStateToProps)(JawabanPencabutanSanksi);

+ 4 - 6
pages/app/pencabutan-sanksi/index.js

@@ -16,10 +16,8 @@ class PencabutanSanksi extends Component {
 	}
 
 	componentDidMount = async () => {
-		const { organisasi, peran } = this.props.user.peran[0];
-		const query = { role: peran.id === 2021 ? "lldikti" : "dikti", cabutSanksi: true };
-		if (peran.id === 2021) query.orgId = organisasi.id;
-		const sanksi = await getSanksi(query);
+		const { token } = this.props;
+		const sanksi = await getSanksi(token, { cabutSanksi: true });
 		this.setState({ sanksi });
 	};
 
@@ -32,12 +30,12 @@ class PencabutanSanksi extends Component {
 					<Col lg="4">
 						<CaseProgress />
 					</Col>
-					<Col lg="8">{sanksi?.data ? <TableSanksi listData={sanksi.data} to="/app/pencabutan-sanksi/detail" linkName="Detail" /> : <Loader />}</Col>
+					<Col lg="8">{sanksi.data ? <TableSanksi listData={sanksi.data} to="/app/pencabutan-sanksi/detail" linkName="Detail" /> : <Loader />}</Col>
 				</Row>
 			</ContentWrapper>
 		);
 	}
 }
 
-const mapStateToProps = (state) => ({ user: state.user });
+const mapStateToProps = (state) => ({ user: state.user, token: state.token });
 export default connect(mapStateToProps)(PencabutanSanksi);

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

@@ -3,7 +3,7 @@ import ContentWrapper from "@/components/Layout/ContentWrapper";
 import { Row, Col } from "reactstrap";
 import { getPelaporan } from "@/actions/pelaporan";
 import CaseProgress from "@/components/Main/CaseProgress";
-import TableLaporan from "@/components/Main/TableLaporan";
+import TableLaporan from "@/components/Penjadwalan/TableLaporan";
 import { connect } from "react-redux";
 import Loader from "@/components/Common/Loader";
 

+ 110 - 42
pages/pt/dokumen-perbaikan/detail.js

@@ -1,6 +1,6 @@
 import React, { Component } from "react";
 import Router from "next/router";
-import { getSanksi } from "@/actions/sanksi";
+import { getOneSanksi } from "@/actions/sanksi";
 import { addDocPerbaikan } from "@/actions/docPerbaikan";
 import Link from "next/link";
 import Header from "@/components/Main/Header";
@@ -13,6 +13,13 @@ import { connect } from "react-redux";
 import { notifDocPerbaikan } from "@/actions/notifikasi";
 import Loader from "@/components/Common/Loader";
 import { toast } from "react-toastify";
+import { Formik, Form, Field, ErrorMessage } from "formik";
+import * as Yup from "yup";
+
+const perbaikanSchema = Yup.object().shape({
+	keterangan: Yup.string().min(3).max(200).required("Harap diisi"),
+	dokumen: Yup.array().min(1).required("Harap diisi"),
+});
 
 let Dropzone = null;
 class DropzoneWrapper extends Component {
@@ -35,18 +42,22 @@ class DetailPerbaikanDoc extends Component {
 			files: [],
 			sanksi: {},
 			keterangan: "",
+			pt: null,
 		};
 	}
 
 	static getInitialProps = ({ query }) => ({ query });
 
 	componentDidMount = async () => {
-		const { user } = this.props;
-		const { noSanksi } = this.props.query;
-		const sanksi = await getSanksi({ noSanksi, ptId: user.peran[0].organisasi.id });
-		this.setState({ sanksi });
+		const { token, query } = this.props;
+		const sanksi = await getOneSanksi(token, query.id);
+		this.setState({ sanksi, pt: sanksi.data.laporan.pt });
 	};
 
+	componentShouldUpdate(nextProps, nextState) {
+		return nextState.sanksi !== this.state.sanksi;
+	}
+
 	onDrop = (files) => {
 		this.setState({
 			files: files.map((file) =>
@@ -77,32 +88,31 @@ class DetailPerbaikanDoc extends Component {
 		});
 	};
 
-	handleKirim = async (e) => {
-		e.preventDefault();
-		const { keterangan, sanksi } = this.state;
-		const { noSanksi } = this.props.query;
-		const { user } = this.props;
-		const org_id = user.peran[0].organisasi.id;
+	handleKirim = async (data, { resetForm }) => {
+		const { token, query } = this.props;
+		const { id } = query;
 		const formdata = new FormData();
-		formdata.append("description", keterangan);
-		if (this.state.files.length > 0) {
-			this.state.files.forEach((e) => {
-				formdata.append("files", e);
-			});
-			const id = toast.loading("Please wait...");
-			const added = await addDocPerbaikan({ noSanksi, ptId: org_id }, formdata);
-			if (added) {
-				await notifDocPerbaikan({ lembaga: sanksi.data[0].sanksi.user.lembaga, pt_name: user.peran[0].organisasi.nama, no_sanksi: sanksi.data[0].sanksi.no_sanksi });
-				toast.update(id, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
-				Router.push({
-					pathname: "/app/pt/dokumen-perbaikan",
-				});
-			}
+		formdata.append("keterangan", data.keterangan);
+		this.state.files.forEach((e) => {
+			formdata.append("dokumen", e);
+		});
+		const toastid = toast.loading("Please wait...");
+		const added = await addDocPerbaikan(token, id, formdata);
+		if (!added) {
+			toast.update(toastid, { render: "All is not good", type: "error", isLoading: false, autoClose: true, closeButton: true });
+		} else {
+			toast.update(toastid, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
+			const sanksi = await getOneSanksi(token, id);
+			this.setState({ sanksi, files: [] });
+			resetForm();
+			// Router.push({
+			// 	pathname: "/app/pt/dokumen-perbaikan",
+			// });
 		}
 	};
 
 	render() {
-		const { files, sanksi } = this.state;
+		const { files, sanksi, pt } = this.state;
 
 		const thumbs = files.map((file, index) => (
 			<Col md={3} key={index}>
@@ -112,32 +122,90 @@ class DetailPerbaikanDoc extends Component {
 
 		return (
 			<ContentWrapper unwrap>
-				<Header data={this.props.pt[0]} />
+				{pt && <Header data={pt} />}
 				<div className="p-3">
 					<div className="content-heading">
 						<div>Dokumen Perbaikan</div>
 						<div className="ml-auto">
-							<Link href="/app/pt/dokumen-perbaikan">
+							<Link href="/pt/dokumen-perbaikan">
 								<button className="btn btn-sm btn-secondary text-sm">&lt; back</button>
 							</Link>
 						</div>
 					</div>
 					<Row>
-						{sanksi?.data ? (
+						{sanksi.data ? (
 							<Col xl="9">
 								<Card className="card-default">
 									<CardBody>
 										<Row>
 											<Col lg={12}>
-												<DetailSanksi data={sanksi.data[0]} />
+												<DetailSanksi data={sanksi.data} />
 												<p className="lead bb">Dokumen Perbaikan</p>
-												<form className="form-horizontal" method="get" action="/" onSubmit={this.onSubmit}>
-													<FormGroup>
-														<label className="row-form-label">Keterangan:</label>
-														<div className="row-md-10">
-															<Input type="textarea" value={this.state.keterangan} onChange={(e) => this.setState({ keterangan: e.target.value })} required />
-														</div>
-													</FormGroup>
+												<Formik
+													initialValues={{
+														keterangan: "",
+														dokumen: [],
+													}}
+													validationSchema={perbaikanSchema}
+													onSubmit={this.handleKirim}
+												>
+													{() => (
+														<Form className="form-horizontal">
+															<FormGroup>
+																<label className="row-form-label">Keterangan Jawaban:</label>
+																<div className="row-md-10">
+																	<Field name="keterangan">{({ field }) => <Input type="textarea" {...field} />}</Field>
+																	<ErrorMessage name="keterangan" component="div" className="form-text text-danger" />
+																	{/* <span className="form-text">Deskripsi pelaporan minimum karakter 50 maksimum 200 karakter</span> */}
+																</div>
+															</FormGroup>
+															<FormGroup>
+																<label className="row-form-label">Upload Dokumen:</label>
+																<div className="row-md-10">
+																	<Field name="dokumen">
+																		{({ field, form }) => (
+																			<DropzoneWrapper
+																				className=""
+																				onDrop={(e) => {
+																					this.onDrop(e);
+																					form.setFieldValue(field.name, e);
+																				}}
+																			>
+																				{({ getRootProps, getInputProps, isDragActive }) => {
+																					return (
+																						<div {...getRootProps()} className={"dropzone card p-3 " + (isDragActive ? "dropzone-drag-active" : "")}>
+																							<input {...getInputProps()} />
+																							<div className="dropzone-previews flex">
+																								{this.state.files.length > 0 ? <Row>{thumbs}</Row> : <div className="text-center dz-default dz-message">Drop files here to upload</div>}
+																							</div>
+																							<div className="d-flex align-items-center">
+																								<small className="ml-auto">
+																									<button type="button" className="btn btn-link" onClick={this.clearFiles}>
+																										Clear files
+																									</button>
+																								</small>
+																							</div>
+																						</div>
+																					);
+																				}}
+																			</DropzoneWrapper>
+																		)}
+																	</Field>
+																	<ErrorMessage name="dokumen" component="div" className="form-text text-danger" />
+																</div>
+															</FormGroup>
+															<FormGroup row>
+																<div className="col-xl-10">
+																	<Button color="primary" type="submit">
+																		Kirim
+																	</Button>
+																</div>
+															</FormGroup>
+														</Form>
+													)}
+												</Formik>
+												{/* <form className="form-horizontal" method="get" action="/" onSubmit={this.onSubmit}>
+													
 													<FormGroup>
 														<label className="row-form-label">Upload Dokumen:</label>
 														<div className="row-md-10">
@@ -169,7 +237,7 @@ class DetailPerbaikanDoc extends Component {
 															</Button>
 														</div>
 													</FormGroup>
-												</form>
+												</form> */}
 											</Col>
 										</Row>
 									</CardBody>
@@ -178,12 +246,12 @@ class DetailPerbaikanDoc extends Component {
 						) : (
 							<Loader />
 						)}
-						<Col xl="3">{this.props.pt && <DetailPT data={this.props.pt[0]} />}</Col>
+						<Col xl="3">{pt && <DetailPT data={pt} />}</Col>
 					</Row>
-					{sanksi?.data && (
+					{sanksi.data && (
 						<Row>
 							<Col>
-								<Riwayat data={sanksi.data[0].sanksi.doc_perbaikan} />
+								<Riwayat data={sanksi.data.perbaikan || []} />
 							</Col>
 						</Row>
 					)}
@@ -193,5 +261,5 @@ class DetailPerbaikanDoc extends Component {
 	}
 }
 
-const mapStateToProps = (state) => ({ user: state.user, pt: state.pt });
+const mapStateToProps = (state) => ({ user: state.user, token: state.token });
 export default connect(mapStateToProps)(DetailPerbaikanDoc);

+ 1 - 1
pages/pt/dokumen-perbaikan/index.js

@@ -26,7 +26,7 @@ class Pelaporan extends Component {
 			<ContentWrapper>
 				<div className="content-heading">Dokumen Perbaikan</div>
 				<Row>
-					<Col lg={12}>{sanksi.data?.length ? <TableSanksi listData={sanksi.data} to="/pt/dokumen-perbaikan/detail" linkName="Detail" /> : sanksi.data ? "Tidak ada Sanksi" : <Loader />}</Col>
+					<Col lg={12}>{sanksi.data?.length ? <TableSanksi listData={sanksi.data} to="/pt/dokumen-perbaikan/detail" linkName="Detail" /> : sanksi.data ? "" : <Loader />}</Col>
 				</Row>
 			</ContentWrapper>
 		);

+ 16 - 14
pages/pt/jawaban-banding/detail.js

@@ -1,6 +1,6 @@
 import React, { Component } from "react";
 import ContentWrapper from "@/components/Layout/ContentWrapper";
-import { getSanksi } from "@/actions/sanksi";
+import { getOneSanksi } from "@/actions/sanksi";
 import Header from "@/components/Main/Header";
 import DetailPT from "@/components/Main/DetailPT";
 import DetailSanksi from "@/components/Main/DetailSanksi";
@@ -17,39 +17,41 @@ class JawabanBanding extends Component {
 		this.state = {
 			modal: false,
 			sanksi: {},
+			pt: null,
 		};
 	}
 
+	static getInitialProps = ({ query }) => ({ query });
+
 	componentDidMount = async () => {
-		const { user } = this.props;
-		const { noSanksi } = this.props.router.query;
-		const sanksi = await getSanksi({ noSanksi, ptId: user.peran[0].organisasi.id });
-		this.setState({ sanksi });
+		const { token, query } = this.props;
+		const sanksi = await getOneSanksi(token, query.id);
+		this.setState({ sanksi, pt: sanksi.data.laporan.pt });
 	};
 
 	render() {
-		const { sanksi } = this.state;
+		const { sanksi, pt } = this.state;
 		return (
 			<ContentWrapper unwrap>
-				<Header data={this.props.pt[0]} />
+				{pt && <Header data={pt} />}
 				<div className="p-3">
 					<div className="content-heading">
 						<div>Jawaban Atas Permohonan Banding</div>
 						<div className="ml-auto">
-							<Link href="/app/pt/jawaban-banding">
+							<Link href="/pt/jawaban-banding">
 								<button className="btn btn-sm btn-secondary text-sm">&lt; back</button>
 							</Link>
 						</div>
 					</div>
 					<Row>
-						{sanksi?.data ? (
+						{sanksi.data ? (
 							<Col xl="9">
 								<Card className="card-default">
 									<CardBody>
 										<Row>
 											<Col lg={12}>
-												<DetailSanksi data={sanksi.data[0]} />
-												<DetailJawaban data={sanksi.data[0]} />
+												<DetailSanksi data={sanksi.data} />
+												<DetailJawaban data={sanksi.data.jawaban.banding} />
 											</Col>
 										</Row>
 									</CardBody>
@@ -58,7 +60,7 @@ class JawabanBanding extends Component {
 						) : (
 							<Loader />
 						)}
-						<Col xl="3">{this.props.pt && <DetailPT data={this.props.pt[0]} />}</Col>
+						<Col xl="3">{pt && <DetailPT data={pt} />}</Col>
 					</Row>
 				</div>
 			</ContentWrapper>
@@ -66,5 +68,5 @@ class JawabanBanding extends Component {
 	}
 }
 
-const mapStateToProps = (state) => ({ user: state.user, pt: state.pt });
-export default connect(mapStateToProps)(withRouter(JawabanBanding));
+const mapStateToProps = (state) => ({ user: state.user, token: state.token });
+export default connect(mapStateToProps)(JawabanBanding);

+ 1 - 1
pages/pt/jawaban-banding/index.js

@@ -16,7 +16,7 @@ class JawabanKeberatan extends Component {
 
 	componentDidMount = async () => {
 		const { token } = this.props;
-		const sanksi = await getSanksi(token, { banding: true, jawaban: true });
+		const sanksi = await getSanksi(token, { banding: true });
 		this.setState({ sanksi });
 	};
 

+ 22 - 20
pages/pt/jawaban-keberatan/detail.js

@@ -1,6 +1,6 @@
 import React, { Component } from "react";
 import ContentWrapper from "@/components/Layout/ContentWrapper";
-import { getSanksi } from "@/actions/sanksi";
+import { getOneSanksi } from "@/actions/sanksi";
 import Header from "@/components/Main/Header";
 import DetailPT from "@/components/Main/DetailPT";
 import DetailSanksi from "@/components/Main/DetailSanksi";
@@ -19,14 +19,16 @@ class JawabanKeberatan extends Component {
 		this.state = {
 			modal: false,
 			sanksi: {},
+			pt: null,
 		};
 	}
 
+	static getInitialProps = ({ query }) => ({ query });
+
 	componentDidMount = async () => {
-		const { user } = this.props;
-		const { noSanksi } = this.props.router.query;
-		const sanksi = await getSanksi({ noSanksi, ptId: user.peran[0].organisasi.id });
-		this.setState({ sanksi });
+		const { token, query } = this.props;
+		const sanksi = await getOneSanksi(token, query.id);
+		this.setState({ sanksi, pt: sanksi.data.laporan.pt });
 	};
 
 	toggleModal = (value = true) => {
@@ -38,37 +40,37 @@ class JawabanKeberatan extends Component {
 	};
 
 	render() {
-		const { sanksi } = this.state;
+		const { sanksi, pt } = this.state;
 		return (
 			<ContentWrapper unwrap>
-				{sanksi?.data && <ModalPermohonan toggleModal={this.toggleModal} modal={this.state.modal} query={this.props.router.query} data={sanksi.data[0]} />}
-				<Header data={this.props.pt[0]} />
+				{sanksi.data && <ModalPermohonan toggleModal={this.toggleModal} modal={this.state.modal} query={this.props.router.query} data={sanksi.data} />}
+				{pt && <Header data={pt} />}
 				<div className="p-3">
 					<div className="content-heading">
 						<div>Jawaban Atas Permohonan Keberatan</div>
 						<div className="ml-auto">
-							<Link href="/app/pt/jawaban-keberatan">
+							<Link href="/pt/jawaban-keberatan">
 								<button className="btn btn-sm btn-secondary text-sm">&lt; back</button>
 							</Link>
 						</div>
 					</div>
 					<Row>
-						{sanksi?.data ? (
+						{sanksi.data ? (
 							<Col xl="9">
 								<Card className="card-default">
 									<CardBody>
 										<Row>
 											<Col lg={12}>
-												<DetailSanksi data={sanksi.data[0]} />
-												<DetailJawaban data={sanksi.data[0]} />
-												{sanksi.data[0].sanksi.keberatan.jawaban.status !== "Membatalkan Keputusan" &&
-													(new Date(sanksi.data[0].sanksi.close_banding).getTime() > Date.now() ? (
+												<DetailSanksi data={sanksi.data} />
+												<DetailJawaban data={sanksi.data.jawaban.keberatan} />
+												{sanksi.data.jawaban.keberatan.status !== "Membatalkan Keputusan" &&
+													(new Date(sanksi.data.batas_waktu.banding).getTime() > Date.now() ? (
 														<>
 															<p>
 																Setelah membaca jawaban permohonan keberatan atas pengenaan sanksi, jika Perguruan Tinggi bermaksud mengajukan permohonan banding kepada atasan pemberi sanksi maka dapat
-																menekan tombol di bawah ini paling lambat {moment(sanksi.data[0].sanksi.close_banding).format("DD MMMM YYYY")}
+																menekan tombol di bawah ini paling lambat {moment(sanksi.data.batas_waktu.banding).format("DD MMMM YYYY")}
 															</p>
-															<Button color="primary" onClick={this.toggleModal} disabled={sanksi.data[0].sanksi.banding || false}>
+															<Button color="primary" onClick={this.toggleModal} disabled={sanksi.data.pengajuan.banding || false}>
 																Ajukan Banding
 															</Button>
 														</>
@@ -83,11 +85,11 @@ class JawabanKeberatan extends Component {
 						) : (
 							<Loader />
 						)}
-						<Col xl="3">{this.props.pt && <DetailPT data={this.props.pt[0]} />}</Col>
+						<Col xl="3">{pt && <DetailPT data={pt} />}</Col>
 					</Row>
-					{sanksi?.data && (
+					{sanksi.data && (
 						<Row>
-							<Col>{sanksi.data[0].sanksi.keberatan.jawaban.status !== "Membatalkan Keputusan" && <Riwayat data={sanksi.data[0]} />}</Col>
+							<Col>{sanksi.data.jawaban.keberatan.status !== "Membatalkan Keputusan" && <Riwayat data={sanksi.data.pengajuan?.banding ? sanksi.data.pengajuan.banding : null} />}</Col>
 						</Row>
 					)}
 				</div>
@@ -96,5 +98,5 @@ class JawabanKeberatan extends Component {
 	}
 }
 
-const mapStateToProps = (state) => ({ user: state.user, pt: state.pt });
+const mapStateToProps = (state) => ({ user: state.user, token: state.token });
 export default connect(mapStateToProps)(withRouter(JawabanKeberatan));

+ 27 - 28
pages/pt/jawaban-pencabutan-sanksi/detail.js

@@ -1,6 +1,6 @@
 import React, { Component } from "react";
 import Link from "next/link";
-import { getSanksi } from "@/actions/sanksi";
+import { getOneSanksi } from "@/actions/sanksi";
 import Header from "@/components/Main/Header";
 import DetailPT from "@/components/Main/DetailPT";
 import DetailSanksi from "@/components/Main/DetailSanksi";
@@ -15,44 +15,41 @@ class DetailJawabanPencabutanSanksi extends Component {
 		super(props);
 		this.state = {
 			sanksi: {},
+			pt: null,
 		};
 	}
 
-	static async getInitialProps({ query }) {
-		return { query };
-	}
+	static getInitialProps = ({ query }) => ({ query });
 
 	componentDidMount = async () => {
-		const { user } = this.props;
-		const { noSanksi } = this.props.query;
-		const sanksi = await getSanksi({ noSanksi, ptId: user.peran[0].organisasi.id });
-		console.log(sanksi);
-		this.setState({ sanksi });
+		const { token, query } = this.props;
+		const sanksi = await getOneSanksi(token, query.id);
+		this.setState({ sanksi, pt: sanksi.data.laporan.pt });
 	};
 
 	render() {
-		const { sanksi } = this.state;
-		const { jawaban } = (sanksi.data && sanksi.data[0].sanksi.cabut_sanksi) || {};
+		const { sanksi, pt } = this.state;
+		const jawaban = sanksi.data?.jawaban.cabut_sanksi || null;
 		return (
 			<ContentWrapper unwrap>
-				<Header data={this.props.pt[0]} />
+				{pt && <Header data={pt} />}
 				<div className="p-3">
 					<div className="content-heading">
 						<div>Jawaban Permohonan Pencabutan Sanksi</div>
 						<div className="ml-auto">
-							<Link href="/app/pt/jawaban-pencabutan-sanksi">
+							<Link href="/pt/jawaban-pencabutan-sanksi">
 								<button className="btn btn-sm btn-secondary text-sm">&lt; back</button>
 							</Link>
 						</div>
 					</div>
 					<Row>
-						{sanksi?.data ? (
+						{sanksi.data ? (
 							<Col xl="9">
 								<Card className="card-default">
 									<CardBody>
 										<Row>
 											<Col lg={12}>
-												<DetailSanksi data={sanksi.data[0]} />
+												<DetailSanksi data={sanksi.data} />
 												<p className="lead bb">Jawaban Permohonan Pencabutan Sanksi</p>
 												<form className="form-horizontal">
 													<FormGroup>
@@ -61,12 +58,14 @@ class DetailJawabanPencabutanSanksi extends Component {
 															<h3>{jawaban && jawaban.status}</h3>
 														</div>
 													</FormGroup>
-													<FormGroup>
-														<label md="4">Keterangan:</label>
-														<div md="8">
-															<p>{jawaban && jawaban.description}</p>
-														</div>
-													</FormGroup>
+													{jawaban && jawaban.keterangan && (
+														<FormGroup>
+															<label md="4">Keterangan:</label>
+															<div md="8">
+																<p>{jawaban.keterangan}</p>
+															</div>
+														</FormGroup>
+													)}
 													<FormGroup>
 														<label md="4">Dokumen Jawaban:</label>
 														<div md="8">
@@ -74,14 +73,14 @@ class DetailJawabanPencabutanSanksi extends Component {
 																<table className="table table-bordered bg-transparent">
 																	<tbody>
 																		{jawaban &&
-																			jawaban.files.map((e) => (
+																			jawaban.dokumen.map((e) => (
 																				<tr>
 																					<td>
 																						<em className="fa-lg far fa-file-code"></em>
 																					</td>
 																					<td>
-																						<a className="text-muted" href={API_URL + e.path} target="_blank" download={e.name}>
-																							{e.name}
+																						<a className="text-muted" href={e.path} target="_blank" download={e.judul}>
+																							{e.judul}
 																						</a>
 																					</td>
 																				</tr>
@@ -95,8 +94,8 @@ class DetailJawabanPencabutanSanksi extends Component {
 												{jawaban && jawaban.status === "Rekomendasi Perbaikan" && (
 													<Link
 														href={{
-															pathname: "/app/pt/dokumen-perbaikan/detail",
-															query: { noSanksi: sanksi.data[0].sanksi.no_sanksi },
+															pathname: "/pt/dokumen-perbaikan/detail",
+															query: { id: sanksi.data._id },
 														}}
 													>
 														<Button color="primary">Perbaiki Dokumen</Button>
@@ -110,7 +109,7 @@ class DetailJawabanPencabutanSanksi extends Component {
 						) : (
 							<Loader />
 						)}
-						<Col xl="3">{this.props.pt && <DetailPT data={this.props.pt[0]} />}</Col>
+						<Col xl="3">{pt && <DetailPT data={pt} />}</Col>
 					</Row>
 				</div>
 			</ContentWrapper>
@@ -118,5 +117,5 @@ class DetailJawabanPencabutanSanksi extends Component {
 	}
 }
 
-const mapStateToProps = (state) => ({ user: state.user, pt: state.pt });
+const mapStateToProps = (state) => ({ user: state.user, token: state.token });
 export default connect(mapStateToProps)(DetailJawabanPencabutanSanksi);

+ 1 - 1
pages/pt/jawaban-pencabutan-sanksi/index.js

@@ -16,7 +16,7 @@ class JawabanCabutSanksi extends Component {
 
 	componentDidMount = async () => {
 		const { token } = this.props;
-		const sanksi = await getSanksi(token, { cabutSanksi: true, jawaban: true });
+		const sanksi = await getSanksi(token, { cabutSanksi: true });
 		this.setState({ sanksi });
 	};
 

+ 2 - 2
pages/pt/keberatan/detail.js

@@ -46,7 +46,7 @@ class Keberatan extends Component {
 					<div className="content-heading">
 						<div>Permohonan Keberatan</div>
 						<div className="ml-auto">
-							<Link href="/app/pt/keberatan">
+							<Link href="/pt/keberatan">
 								<button className="btn btn-sm btn-secondary text-sm">&lt; back</button>
 							</Link>
 						</div>
@@ -85,7 +85,7 @@ class Keberatan extends Component {
 					{sanksi.data && (
 						<Row>
 							<Col>
-								<Riwayat data={sanksi.data?.pengajuan?.keberatan ? sanksi.data.pengajuan.keberatan : {}} />
+								<Riwayat data={sanksi.data?.pengajuan?.keberatan ? sanksi.data.pengajuan.keberatan : null} />
 							</Col>
 						</Row>
 					)}

+ 76 - 52
pages/pt/pencabutan-sanksi/detail.js

@@ -5,14 +5,19 @@ import { getOneSanksi } from "@/actions/sanksi";
 import Header from "@/components/Main/Header";
 import DetailPT from "@/components/Main/DetailPT";
 import DetailSanksi from "@/components/Main/DetailSanksi";
-import Riwayat from "@/components/PT/Riwayat";
+import Riwayat from "@/components/PencabutanSanksi/Riwayat";
 import ContentWrapper from "@/components/Layout/ContentWrapper";
 import { Row, Col, Card, CardBody, FormGroup, Button } from "reactstrap";
 import { addCabutSanksi } from "@/actions/cabutSanksi";
 import { connect } from "react-redux";
 import Loader from "@/components/Common/Loader";
 import { toast } from "react-toastify";
+import { Formik, Form, Field, ErrorMessage } from "formik";
+import * as Yup from "yup";
 
+const docSchema = Yup.object().shape({
+	dokumen: Yup.array().min(1).required("Required"),
+});
 let Dropzone = null;
 class DropzoneWrapper extends Component {
 	state = {
@@ -34,6 +39,7 @@ class DetailPencabutanSanksi extends Component {
 			files: [],
 			sanksi: {},
 			pt: null,
+			error: null,
 		};
 	}
 
@@ -77,24 +83,21 @@ class DetailPencabutanSanksi extends Component {
 		});
 	};
 
-	handleKirim = async (e) => {
-		e.preventDefault();
-		const { noSanksi } = this.props.query;
-		const { user } = this.props;
-		const org_id = user.peran[0].organisasi.id;
+	handleKirim = async (data) => {
+		const { user, query, token } = this.props;
 		const formdata = new FormData();
-		if (this.state.files.length > 0) {
-			this.state.files.forEach((e) => {
-				formdata.append("files", e);
+		data.dokumen.forEach((e) => {
+			formdata.append("dokumen", e);
+		});
+		const id = toast.loading("Please wait...");
+		const added = await addCabutSanksi(token, query.id, formdata);
+		if (!added) {
+			toast.update(id, { render: "All is not good", type: "error", isLoading: false, autoClose: true, closeButton: true });
+		} else {
+			toast.update(id, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
+			Router.push({
+				pathname: "/pt/pencabutan-sanksi",
 			});
-			const id = toast.loading("Please wait...");
-			const added = await addCabutSanksi({ noSanksi, ptId: org_id }, formdata);
-			if (added) {
-				toast.update(id, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
-				Router.push({
-					pathname: "/app/pt/pencabutan-sanksi",
-				});
-			}
 		}
 	};
 
@@ -127,39 +130,60 @@ class DetailPencabutanSanksi extends Component {
 											<Col lg={12}>
 												<DetailSanksi data={sanksi.data} />
 												<p className="lead bb">Permohonan Pencabutan Sanksi</p>
-												<form className="form-horizontal" method="get" action="/" onSubmit={this.onSubmit}>
-													<FormGroup>
-														<label className="row-form-label">Upload Dokumen:</label>
-														<div className="row-md-10">
-															<DropzoneWrapper className="" onDrop={this.onDrop}>
-																{({ getRootProps, getInputProps, isDragActive }) => {
-																	return (
-																		<div {...getRootProps()} className={"dropzone card p-3 " + (isDragActive ? "dropzone-drag-active" : "")}>
-																			<input {...getInputProps()} />
-																			<div className="dropzone-previews flex">
-																				{this.state.files.length > 0 ? <Row>{thumbs}</Row> : <div className="text-center dz-default dz-message">Drop files here to upload</div>}
-																			</div>
-																			<div className="d-flex align-items-center">
-																				<small className="ml-auto">
-																					<button type="button" className="btn btn-link" onClick={this.clearFiles}>
-																						Clear files
-																					</button>
-																				</small>
-																			</div>
-																		</div>
-																	);
-																}}
-															</DropzoneWrapper>
-														</div>
-													</FormGroup>
-													<FormGroup>
-														<div className="row-xl-10">
-															<Button color="primary" onClick={this.handleKirim} disabled={sanksi.data?.pengajuan?.cabut_sanksi ? sanksi.data.pengajuan.cabut_sanksi : false} type="submit">
-																Kirim
-															</Button>
-														</div>
-													</FormGroup>
-												</form>
+												<Formik
+													initialValues={{
+														dokumen: [],
+													}}
+													validationSchema={docSchema}
+													onSubmit={this.handleKirim}
+												>
+													{() => (
+														<Form className="form-horizontal">
+															<FormGroup>
+																<label className="row-form-label">Upload Dokumen:</label>
+																<div className="row-md-10">
+																	<Field name="dokumen">
+																		{({ field, form }) => (
+																			<DropzoneWrapper
+																				className=""
+																				onDrop={(e) => {
+																					this.onDrop(e);
+																					form.setFieldValue(field.name, e);
+																				}}
+																			>
+																				{({ getRootProps, getInputProps, isDragActive }) => {
+																					return (
+																						<div {...getRootProps()} className={"dropzone card p-3 " + (isDragActive ? "dropzone-drag-active" : "")}>
+																							<input {...getInputProps()} />
+																							<div className="dropzone-previews flex">
+																								{this.state.files.length > 0 ? <Row>{thumbs}</Row> : <div className="text-center dz-default dz-message">Drop files here to upload</div>}
+																							</div>
+																							<div className="d-flex align-items-center">
+																								<small className="ml-auto">
+																									<button type="button" className="btn btn-link" onClick={this.clearFiles}>
+																										Clear files
+																									</button>
+																								</small>
+																							</div>
+																						</div>
+																					);
+																				}}
+																			</DropzoneWrapper>
+																		)}
+																	</Field>
+																	<ErrorMessage name="dokumen" component="div" className="form-text text-danger" />
+																</div>
+															</FormGroup>
+															<FormGroup>
+																<div className="row-xl-10">
+																	<Button color="primary" disabled={sanksi.data?.pengajuan?.cabut_sanksi || false} type="submit">
+																		Kirim
+																	</Button>
+																</div>
+															</FormGroup>
+														</Form>
+													)}
+												</Formik>
 											</Col>
 										</Row>
 									</CardBody>
@@ -170,10 +194,10 @@ class DetailPencabutanSanksi extends Component {
 						)}
 						<Col xl="3">{pt && <DetailPT data={pt} />}</Col>
 					</Row>
-					{sanksi?.data && (
+					{sanksi.data && (
 						<Row>
 							<Col>
-								<Riwayat data={sanksi.data?.pengajuan?.cabut_sanksi ? sanksi.data.pengajuan.cabut_sanksi : []} />
+								<Riwayat data={sanksi.data?.pengajuan?.cabut_sanksi || null} />
 							</Col>
 						</Row>
 					)}