Browse Source

update fe ke prod

andi 2 years ago
parent
commit
29f37fef0b
48 changed files with 2193 additions and 156 deletions
  1. 35 0
      actions/autosave.js
  2. 7 1
      actions/sanksi.js
  3. 10 1
      components/Delegasi/CaseProgress.js
  4. 2 0
      components/Extras/calendar.view.js
  5. 1 1
      components/Layout/Footer.js
  6. 23 17
      components/Layout/MenuPT.js
  7. 1 1
      components/Main/DetailSanksi.js
  8. 1 1
      components/NaikSanksi/InputTanggal.js
  9. 11 0
      components/NaikSanksi/TableLaporan.js
  10. 7 13
      components/PT/JawabanKeberatan/ModalPermohonan.js
  11. 12 3
      components/PT/Keberatan/ModalPermohonan.js
  12. 169 0
      components/PT/Sanksi/TableSanksi.js
  13. 8 5
      components/Pelaporan/InputData.js
  14. 1 11
      components/Pemeriksaan/InputEvaluasi.js
  15. 11 0
      components/PerpanjanganSanksi/TableLaporan.js
  16. 2 2
      components/Riwayat/TableRiwayat.js
  17. 1 1
      components/Riwayat/TableRiwayatt.js
  18. 46 0
      components/Sanksi/BeritaAcara_A.js
  19. 78 0
      components/Sanksi/Ringkasan.js
  20. 299 0
      components/Sanksi/SuratBA.js
  21. 40 2
      components/Sanksi/TablePenetapanSanksi.js
  22. 211 5
      components/Sanksi/UploadSurat.js
  23. 11 0
      components/TurunSanksi/TableLaporan.js
  24. 39 0
      package-lock.json
  25. 2 0
      package.json
  26. 180 4
      pages/app/banding/detail.js
  27. 1 1
      pages/app/index.js
  28. 191 12
      pages/app/keberatan/detail.js
  29. 1 0
      pages/app/keberatan/index.js
  30. 38 1
      pages/app/laporan-delegasi/index.js
  31. 19 11
      pages/app/pelaporan/index.js
  32. 24 2
      pages/app/pemeriksaan/index.js
  33. 20 2
      pages/app/penjadwalan/index.js
  34. 20 2
      pages/app/sanksi/index.js
  35. 69 11
      pages/app/sanksi/proses.js
  36. 36 6
      pages/app/tuntas/index.js
  37. 29 6
      pages/pt/jawaban-banding/detail.js
  38. 88 22
      pages/pt/jawaban-keberatan/detail.js
  39. 1 1
      pages/pt/jawaban-keberatan/index.js
  40. 2 0
      pages/pt/jawaban-pencabutan-sanksi/detail.js
  41. 1 1
      pages/pt/jawaban-pencabutan-sanksi/index.js
  42. 67 7
      pages/pt/keberatan/detail.js
  43. 1 1
      pages/pt/keberatan/index.js
  44. 152 0
      pages/pt/sanksi/detail.js
  45. 39 0
      pages/pt/sanksi/index.js
  46. BIN
      public/static/img/Wait-Jawaban.png
  47. 46 0
      styles/bootstrap/_buttons.scss
  48. 140 2
      styles/bootstrap/_progress.scss

+ 35 - 0
actions/autosave.js

@@ -0,0 +1,35 @@
+import axios from "@/config/axios";
+
+export const getAutoSave = async ({ token, laporan, sanksi, id }) => {
+    try {
+        let url = "";
+        if (laporan) {
+            url += `/auto/save/${id}?laporan=true`;
+        }
+        if (sanksi) {
+            url += `/auto/save/${id}?sanksi=true`;
+        }
+        const res = await axios.get(url, { headers: { Authorization: token } });
+        return res.data;
+    } catch (error) {
+        console.log("error", error);
+        return false;
+    }
+};
+
+export const inputAutoSave = async ({ token, laporan, sanksi, id, data }) => {
+    try {
+        let url = "";
+        if (laporan) {
+            url += `/auto/save/${id}?laporan=true`;
+        }
+        if (sanksi) {
+            url += `/auto/save/${id}?sanksi=true`;
+        }
+        const res = await axios.post(url, data, { headers: { Authorization: token } });
+        return res.data;
+    } catch (error) {
+        console.log("error", error);
+        return false;
+    }
+};

+ 7 - 1
actions/sanksi.js

@@ -12,7 +12,7 @@ export const getSanksi = async (token, query = {}) => {
 	try {
 		let url = "/sanksi";
 		if (query != {}) {
-			const { keberatan, jawaban, banding, cabutSanksi, perbaikan, aktif, delegasi, turunSanksi, naikSanksi } = query;
+			const { keberatan, jawaban, banding, cabutSanksi, perbaikan, aktif, delegasi, turunSanksi, naikSanksi, pengajuan_keberatan, is_pengajuan_keberatan, is_pengajuan_banding } = query;
 			url += "?";
 			const parseURL = [];
 			if (keberatan) parseURL.push(`keberatan=true`);
@@ -24,6 +24,7 @@ export const getSanksi = async (token, query = {}) => {
 			if (turunSanksi) parseURL.push(`turunSanksi=true`);
 			if (naikSanksi) parseURL.push(`naikSanksi=true`);
 			if (aktif === false) parseURL.push(`aktif=false`);
+			if (is_pengajuan_keberatan) parseURL.push(`pengajuan_keberatan=true`);
 			url += parseURL.join("&");
 		}
 
@@ -76,3 +77,8 @@ export const update = async (token, id, data) => {
 	await createLog(token, { aktivitas: `Berhasil Merubah Sanksi, id: ${id}` });
 	return res.data;
 };
+export const updatePT = async (token, id, data) => {
+	const res = await axiosAPI.put(`/sanksi/update-pt/${id}`, data, { headers: { Authorization: token } });
+	await createLog(token, { aktivitas: `Berhasil mengubah status sanksi, id: ${id}` });
+	return res.data;
+};

+ 10 - 1
components/Delegasi/CaseProgress.js

@@ -9,7 +9,7 @@ import Datatable from "@/components/Tables/Datatable";
 import MorrisChart from "@/components/Charts//Morris";
 import Dropdown from 'react-bootstrap/Dropdown';
 
-function CaseProgress({ data, nextButton, prevButton, tahun, excel }) {
+function CaseProgress({ data, nextButton, prevButton, tahun, excel, excelSemua, excelMenu }) {
 	const ChartPie = {
 		data: [
 			{
@@ -117,6 +117,15 @@ function CaseProgress({ data, nextButton, prevButton, tahun, excel }) {
 						<img src="/static/img/next.png"></img>
 					</Button>
 					<b className="text-tahun">Tahun {tahun} </b>
+					<Dropdown className="float-right">
+						<Dropdown.Toggle variant="success" id="dropdown-basic">
+							Unduh
+						</Dropdown.Toggle>
+						<Dropdown.Menu>
+							<Dropdown.Item onClick={excelMenu}>Unduh dokumen pelaporan</Dropdown.Item>
+							<Dropdown.Item onClick={excelSemua}>Unduh dokumen semua menu</Dropdown.Item>
+						</Dropdown.Menu>
+					</Dropdown>
 					{/* <Button className="float-right button-hidden icon-eksport" type="submit" onClick={excel}>
 						<img src="/static/img/eksport.png"></img>
 					</Button> */}

+ 2 - 0
components/Extras/calendar.view.js

@@ -314,6 +314,7 @@ class Calendar extends Component {
 																						locale="en-gb"
 																						inputProps={{ className: "form-control" }}
 																						value={field.value}
+																						closeOnSelect={true}
 																						onChange={(e) => {
 																							form.setFieldValue(field.name, e.format("DD MMMM YYYY"));
 																						}}
@@ -333,6 +334,7 @@ class Calendar extends Component {
 																						locale="en-gb"
 																						inputProps={{ className: "form-control" }}
 																						value={field.value}
+																						closeOnSelect={true}
 																						onChange={(e) => {
 																							form.setFieldValue(field.name, e.format("DD MMMM YYYY"));
 																						}}

+ 1 - 1
components/Layout/Footer.js

@@ -7,7 +7,7 @@ class Footer extends Component {
         return (
             <footer className="footer-container">
                 <span>Sidali Dikti &copy; {year}</span>
-                <span className=' float-right'>Version 2.2 ~ 1.96</span>
+                <span className=' float-right'>Version 2.13 ~ 2.12</span>
             </footer>
         );
     }

+ 23 - 17
components/Layout/MenuPT.js

@@ -10,24 +10,30 @@ const MenuPT = [
 		translate: "sidebar.nav.PT_PEMANTAUAN",
 	},
 	{
-		name: "Pengajuan Keberatan",
-		icon: "icon-hourglass",
-		translate: "sidebar.nav.PENGAJUAN_KEBERATAN",
-		submenu: [
-			{
-				name: "a. Permohonan Keberatan",
-				path: "/pt/keberatan",
-			},
-			{
-				name: "b. Jawaban keberatan",
-				path: "/pt/jawaban-keberatan",
-			},
-			{
-				name: "c. Jawaban banding",
-				path: "/pt/jawaban-banding",
-			},
-		],
+		name: "Sanksi",
+		path: "/pt/sanksi",
+		icon: "icon-social-steam",
+		translate: "sidebar.nav.PT_PEMANTAUAN",
 	},
+	// {
+	// 	name: "Pengajuan Keberatan",
+	// 	icon: "icon-hourglass",
+	// 	translate: "sidebar.nav.PENGAJUAN_KEBERATAN",
+	// 	submenu: [
+	// 		{
+	// 			name: "a. Permohonan Keberatan",
+	// 			path: "/pt/keberatan",
+	// 		},
+	// 		{
+	// 			name: "b. Jawaban keberatan",
+	// 			path: "/pt/jawaban-keberatan",
+	// 		},
+	// 		{
+	// 			name: "c. Jawaban banding",
+	// 			path: "/pt/jawaban-banding",
+	// 		},
+	// 	],
+	// },
 	{
 		name: "Dokumen Perbaikan",
 		path: "/pt/dokumen-perbaikan",

+ 1 - 1
components/Main/DetailSanksi.js

@@ -32,7 +32,7 @@ function DetailSanksi({ data, noTitle = false }) {
 				<FormGroup row>
 					<Col md="4">Dibuat Pada:</Col>
 					<Col md="8">
-						<strong>{moment(data.createdAt).format("D MMMM YYYY")}</strong>
+						<strong>{moment(data.createdAt).locale("id").format("D MMMM YYYY")}</strong>
 					</Col>
 				</FormGroup>
 				<FormGroup row>

+ 1 - 1
components/NaikSanksi/InputTanggal.js

@@ -46,7 +46,7 @@ const rekomendasiSchema = Yup.object().shape({
     no_sanksi: Yup.string().required("Wajib isi Nomor Sanksi"),
     keterangan: Yup.string().min(3, "Minimal 3 Huruf").max(200).required("Wajib isi keterangan"),
     from_date: Yup.date().required("Wajib diisi"),
-    to_date: Yup.date().required("Wajib diisi"),
+    to_date: Yup.date().notRequired("Wajib diisi"),
     sanksi: Yup.array().required("Wajib isi pelanggaran"),
     dokumen: Yup.array().required("Wajib diisi").test("filesize", "Maksimal ukuran dokumen 15mb", checkIfFilesAreTooBig),
 });

+ 11 - 0
components/NaikSanksi/TableLaporan.js

@@ -15,6 +15,7 @@ function TableLaporan({ listData, to, linkName, status = false, noBy = false })
 							<thead>
 								<tr>
 									<th>No.Laporan</th>
+									<th>No.Sanksi</th>
 									<th>Deskripsi Laporan</th>
 									{<th>TMT Berlaku</th>}
 									{/* {!noBy && <th>Dibuat Oleh</th>} */}
@@ -37,6 +38,16 @@ function TableLaporan({ listData, to, linkName, status = false, noBy = false })
 													</div>
 												</div>
 											</td>
+											<td>
+												{/* <td>{data.no_laporan}</td> */}
+												<div className="media align-items-center">
+													<div className="media-body d-flex">
+														<div>
+															<h4>{data.no_sanksi}</h4>
+														</div>
+													</div>
+												</div>
+											</td>
 
 											<td>
 												<div className="table-desc">

+ 7 - 13
components/PT/JawabanKeberatan/ModalPermohonan.js

@@ -6,6 +6,8 @@ import { connect } from "react-redux";
 import { toast } from "react-toastify";
 import { Formik, Form, Field, ErrorMessage } from "formik";
 import * as Yup from "yup";
+import { updatePT } from "@/actions/sanksi";
+
 
 let Dropzone = null;
 class DropzoneWrapper extends Component {
@@ -109,13 +111,16 @@ export class ModalPermohonan extends Component {
 
 		const toastid = toast.loading("Please wait...");
 		const added = await addBanding(token, id, formdata);
-
+		await updatePT(token, query.id, { is_pengajuan_banding: true })
+		Router.push({
+			pathname: "/pt/jawaban-banding/detail", query: { id: id }
+		});
 		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: "/pt/jawaban-banding",
+				pathname: "/pt/jawaban-banding/detail", query: { id: id }
 			});
 		}
 	};
@@ -139,17 +144,6 @@ export class ModalPermohonan extends Component {
 		return (
 			<>
 				<Modal isOpen={this.props.modal} toggle={this.props.toggleModal}>
-					<ModalBody>Apakah anda akan mengajukan banding?</ModalBody>
-					<ModalFooter>
-						<Button color className="btn-login" onClick={this.toggleModal1}>
-							<span className="font-color-white">Ya</span>
-						</Button>{" "}
-						<Button color className="btn-v2" onClick={this.props.toggleModal}>
-							Tidak
-						</Button>
-					</ModalFooter>
-				</Modal>
-				<Modal isOpen={this.state.modal1} toggle={this.toggleModal1}>
 					<ModalHeader toggle={this.toggleModal1}>Upload Dokumen Banding</ModalHeader>
 					<Formik
 						initialValues={{

+ 12 - 3
components/PT/Keberatan/ModalPermohonan.js

@@ -6,6 +6,7 @@ import { connect } from "react-redux";
 import { toast } from "react-toastify";
 import { Formik, Form, Field, ErrorMessage } from "formik";
 import * as Yup from "yup";
+import Link from "next/link";
 
 let Dropzone = null;
 class DropzoneWrapper extends Component {
@@ -111,19 +112,22 @@ export class ModalPermohonan extends Component {
 
 		const tostid = toast.loading("Please wait...");
 		const success = await addKeberatan(token, id, formdata);
-
+		Router.push({
+			pathname: "/pt/jawaban-keberatan/detail", query: { id: id }
+		});
 		if (!success) {
 			toast.update(tostid, { render: "All is not good", type: "error", isLoading: false, autoClose: true, closeButton: true });
 		} else {
 			toast.update(tostid, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
 			Router.push({
-				pathname: "/pt/jawaban-keberatan",
+				pathname: "/pt/jawaban-keberatan/detail", query: { id: id }
 			});
 		}
 	};
 
 	render() {
 		const { files } = this.state;
+		const { sanksi } = this.props
 
 		const removeFile = file => () => {
 			const newFiles = [...files]
@@ -142,14 +146,17 @@ export class ModalPermohonan extends Component {
 			<>
 				<Modal isOpen={this.props.modal} toggle={this.props.toggleModal}>
 					<ModalBody>Apakah anda akan mengajukan permohonan keberatan atas pengenaan sanksi?</ModalBody>
+
 					<ModalFooter>
+
 						<Button color className="btn-login" onClick={this.toggleModal1}>
 							<span className="font-color-white">Ya</span>
-						</Button>{" "}
+						</Button>
 						<Button color className="btn-v2" onClick={this.props.toggleModal}>
 							Tidak
 						</Button>
 					</ModalFooter>
+
 				</Modal>
 				<Modal isOpen={this.state.modal1} toggle={this.toggleModal1}>
 					<ModalHeader toggle={this.toggleModal1}>Unggah Dokumen Permohonan Keberatan</ModalHeader>
@@ -222,9 +229,11 @@ export class ModalPermohonan extends Component {
 								</FormGroup>
 							</ModalBody>
 							<ModalFooter>
+
 								<Button color className="btn-login" type="submit">
 									<span className="font-color-white">Kirim</span>
 								</Button>
+
 							</ModalFooter>
 						</Form>
 					</Formik>

+ 169 - 0
components/PT/Sanksi/TableSanksi.js

@@ -0,0 +1,169 @@
+import moment from "moment";
+import { Button, Table } from "reactstrap";
+import Link from "next/link";
+
+function TableSanksi({ listData, to, linkName, toKeberatan, toJwbBanding, toJwbKeberatan, toPerbaikan, toJwbBanding2, toCabutSanksi, toJwbCabutSanksi }) {
+	return (
+		<div className="card b">
+			<div className="card-body card-over">
+				<Table className="table w-100">
+					<thead>
+						<tr>
+							<th>Nomor Sanksi</th>
+							<th>Keterangan Sanksi</th>
+							{/* <th>Created</th> */}
+							<th>Status</th>
+						</tr>
+					</thead>
+					<tbody>
+						{listData.map((data) => {
+							return (
+								<tr key={data._id}>
+									{/* <td>{data.no_sanksi}</td> */}
+									<td>
+										<div className="media align-items-center">
+											<div className="media-body d-flex">
+												<div>
+													<h4>{data.no_sanksi}</h4>
+													<p>{moment(data.createdAt).format("DD-MM-YYYY")}</p>
+												</div>
+											</div>
+										</div>
+									</td>
+									<td>
+										<div className="table-desc">
+											<div className="media align-items-center">
+												<div className="media-body d-flex">
+													<div>
+														<h4 className="m-0">{data.laporan.pt.nama.length > 64 ? data.laporan.pt.nama.substring(0, 64) + "..." : data.laporan.pt.nama}</h4>
+														<p className="w-105">{data.keterangan}</p>
+													</div>
+												</div>
+											</div>
+										</div>
+									</td>
+									{/* <td>{moment(data.createdAt).format("DD MMMM YYYY")}</td> */}
+									<td>{data.is_pengajuan_keberatan === true || data.is_pengajuan_keberatan === false ? <div className="badge badge-green">{data.last_step}</div> : <div className="badge badge-red">Belum Diperiksa</div>}</td>
+									{/* <td>{data.pengajuan?.keberatan ?
+										<Link href={{ pathname: toKeberatan, query: { id: data._id } }}>
+											<Button className="btn-login" color >
+												<span className="font-color-white">
+													{linkName}
+												</span>
+											</Button>
+										</Link> :
+										<Link href={{ pathname: to, query: { id: data._id } }}>
+											<Button className="btn-login" color >
+												<span className="font-color-white">
+													{linkName}
+												</span>
+											</Button>
+										</Link>
+									}
+									</td> */}
+									<td>
+										{data.last_step === "Permohonan Keberatan" && (
+
+											<Link href={{ pathname: toKeberatan, query: { id: data._id } }}>
+												<Button className="btn-login" color >
+													<span className="font-color-white">
+														{linkName}
+													</span>
+												</Button>
+											</Link>
+
+										)}
+										{data.last_step === "Jawaban Atas Permohonan Keberatan" && (
+
+											<Link href={{ pathname: toJwbKeberatan, query: { id: data._id } }}>
+												<Button className="btn-login" color >
+													<span className="font-color-white">
+														{linkName}
+													</span>
+												</Button>
+											</Link>
+
+										)}
+										{data.last_step === "Jawaban Atas Permohonan Banding" && (
+
+											<Link href={{ pathname: toJwbBanding, query: { id: data._id } }}>
+												<Button className="btn-login" color >
+													<span className="font-color-white">
+														{linkName}
+													</span>
+												</Button>
+											</Link>
+
+										)}
+										{data.last_step === "Permohonan Banding" && (
+
+											<Link href={{ pathname: toJwbBanding2, query: { id: data._id } }}>
+												<Button className="btn-login" color >
+													<span className="font-color-white">
+														{linkName}
+													</span>
+												</Button>
+											</Link>
+
+										)}
+										{data.last_step === "Permohonan Pencabutan Sanksi" && (
+
+											<Link href={{ pathname: toCabutSanksi, query: { id: data._id } }}>
+												<Button className="btn-login" color >
+													<span className="font-color-white">
+														{linkName}
+													</span>
+												</Button>
+											</Link>
+
+										)}
+										{data.last_step === "Jawaban Atas Permohonan Pencabutan Sanksi" && (
+
+											<Link href={{ pathname: toJwbCabutSanksi, query: { id: data._id } }}>
+												<Button className="btn-login" color >
+													<span className="font-color-white">
+														{linkName}
+													</span>
+												</Button>
+											</Link>
+
+										)}
+
+
+										{data.last_step === "Dokumen Perbaikan" && (
+
+											<Link href={{ pathname: toPerbaikan, query: { id: data._id } }}>
+												<Button className="btn-login" color >
+													<span className="font-color-white">
+														{linkName}
+													</span>
+												</Button>
+											</Link>
+
+										)}
+										{data.last_step ? (
+
+											""
+
+										) : (
+											<Link href={{ pathname: to, query: { id: data._id } }}>
+												<Button className="btn-login" color >
+													<span className="font-color-white">
+														{linkName}
+													</span>
+												</Button>
+											</Link>
+										)}
+									</td>
+
+								</tr>
+							);
+						})}
+					</tbody>
+				</Table>
+			</div>
+		</div>
+	);
+}
+
+export default TableSanksi;

+ 8 - 5
components/Pelaporan/InputData.js

@@ -137,11 +137,14 @@ export class InputData extends Component {
 		formdata.append("pt_id", query.ptId);
 		formdata.append("keterangan", data.keterangan);
 		formdata.append("pelanggaran_id", data.pelanggaran.join());
-		if (data.dokumen.length > 0) {
-			data.dokumen.forEach((e) => {
-				formdata.append("dokumen", e);
-			});
-		}
+		// if (data.dokumen.length > 0) {
+		// 	data.dokumen.forEach((e) => {
+		// 		formdata.append("dokumen", e);
+		// 	});
+		// }
+		this.state.files.forEach((e) => {
+			formdata.append("dokumen", e);
+		});
 
 		const create = createPelaporan(token, formdata);
 		await toast.promise(create, {

+ 1 - 11
components/Pemeriksaan/InputEvaluasi.js

@@ -126,7 +126,7 @@ class InputEvaluasi extends Component {
 		const formdata = new FormData();
 		formdata.append("judul", data.judul);
 		formdata.append("tanggal", data.tanggal);
-		data.dokumen.forEach((e) => {
+		this.state.files.forEach((e) => {
 			formdata.append("dokumen", e);
 		});
 		if (this.state.delegasichecklist == true) {
@@ -171,16 +171,6 @@ class InputEvaluasi extends Component {
 			});
 		}
 		const thumbs = files.map((file, index) => (
-			// <div md={3} key={index}>
-			// 	<div className="text-left">{file.name}</div>
-			// 	<div><button className="bg-transparent button-transparent border-0 float-right" onClick={removeFile(file)}>
-			// 		<em className="fas fa-trash"></em>
-			// 	</button>
-			// 		{/* <Progress color="info" value={100}>Success</Progress> */}
-			// 	</div>
-			// 	<span className="float-right">
-			// 	</span>
-			// </div>
 			<p>
 				<em className="far fa-file" />&nbsp;&nbsp;{file.name}
 				<button className="bg-transparent button-transparent border-0 fas fa-trash text-danger float-right" onClick={removeFile(file)} />

+ 11 - 0
components/PerpanjanganSanksi/TableLaporan.js

@@ -15,6 +15,7 @@ function TableLaporan({ listData, to, linkName, status = false, noBy = false })
 							<thead>
 								<tr>
 									<th>No.Laporan</th>
+									<th>No.Sanksi</th>
 									<th>Deskripsi Laporan</th>
 									{<th>TMT Berlaku</th>}
 									<th>Aksi</th>
@@ -35,6 +36,16 @@ function TableLaporan({ listData, to, linkName, status = false, noBy = false })
 													</div>
 												</div>
 											</td>
+											<td>
+												{/* <td>{data.no_laporan}</td> */}
+												<div className="media align-items-center">
+													<div className="media-body d-flex">
+														<div>
+															<h4>{data.no_sanksi}</h4>
+														</div>
+													</div>
+												</div>
+											</td>
 
 											<td>
 												<div className="table-desc">

+ 2 - 2
components/Riwayat/TableRiwayat.js

@@ -19,8 +19,8 @@ class TableRiwayat extends Component {
 
 		this._columns = [
 			{
-				key: "timelapse",
-				name: "Timelapse",
+				key: "timestamp",
+				name: "Timestamp",
 				sortable: true,
 				// width: 150
 			},

+ 1 - 1
components/Riwayat/TableRiwayatt.js

@@ -32,7 +32,7 @@ class TableRiwayatt extends Component {
                             <table className="table w-100" data-order='[[3, "desc"]]'>
                                 <thead>
                                     <tr>
-                                        <th>Timelapse</th>
+                                        <th>Timestamp</th>
                                         <th>Username</th>
                                         <th>IPv4</th>
                                         <th>Menu</th>

+ 46 - 0
components/Sanksi/BeritaAcara_A.js

@@ -0,0 +1,46 @@
+import React, { useRef, Component } from 'react';
+import { useReactToPrint } from "react-to-print";
+import { Row, Col, Button } from "reactstrap";
+import Head from 'next/head'
+import SignatureCanvas from 'react-signature-canvas'
+import ComponentToPrint from "./SuratBA";
+import ReactToPrint, { PrintContextConsumer } from 'react-to-print';
+import { getOneLaporan, updateLaporan } from "@/actions/pelaporan";
+
+
+class BeritaAcara extends Component {
+    constructor(props) {
+        super(props);
+        this.state = {
+        };
+    }
+    static getInitialProps = async ({ query }) => {
+        return { query };
+    };
+
+    render() {
+        return (
+            <div>
+                <ReactToPrint pageStyle='print' content={() => this.componentRef}>
+                    <PrintContextConsumer>
+                        {({ handlePrint }) => (
+                            <div className=' content-heading border-radius-login'>
+                                <span className="btn-radius">
+                                    <Button onClick={handlePrint} color className="btn-labeled-4">
+                                        <h4 className="p-0 mt-2">Print dan Download</h4>
+                                    </Button>
+                                </span>
+                            </div>
+
+                        )}
+                    </PrintContextConsumer>
+                </ReactToPrint>
+                {/* <div style={{ display: "none" }}> */}
+                <ComponentToPrint ref={el => (this.componentRef = el)} query={this.props.query} dataPelanggaran={this.props.dataPelanggaran} />
+                {/* </div> */}
+            </div >
+
+        );
+    }
+}
+export default BeritaAcara

+ 78 - 0
components/Sanksi/Ringkasan.js

@@ -193,6 +193,84 @@ function Ringkasan({ dataLaporan, dataPelanggaran, dataUpload }) {
 								</Scrollable>
 							</Col>
 						</FormGroup>
+						<FormGroup row>
+							<Col md="4">Surat Berita Acara:</Col>
+							<Col md="8">
+								<Scrollable height="120px" className="list-group">
+									<table className="table table-bordered bg-transparent">
+										<tbody>
+											{dataUpload
+												? dataUpload.filesBeritaAcara.map((e) => (
+													<tr>
+														<td>
+															<em className="fa-lg far fa-file-code"></em>
+														</td>
+														<td>
+															<a className="text-muted" href={e.preview} download={e.name}>
+																{e.name}
+															</a>
+														</td>
+													</tr>
+												))
+												: ""}
+										</tbody>
+									</table>
+								</Scrollable>
+							</Col>
+						</FormGroup>
+						<FormGroup row>
+							<Col md="4">Tanggal Terima Surat Sanksi :</Col>
+							<Col md="8">
+								<strong>
+									{dataUpload && dataUpload.terimaSuratSanksi ? (
+										<p>
+											{moment(dataUpload.terimaSuratSanksi).locale("id").format("DD MMMM YYYY")}
+										</p>
+									) : (
+										""
+									)}
+								</strong>
+							</Col>
+						</FormGroup>
+						<FormGroup row>
+							<Col md="4">Dokumen Tanda Terima Surat Sanksi:</Col>
+							<Col md="8">
+								<Scrollable height="120px" className="list-group">
+									<table className="table table-bordered bg-transparent">
+										<tbody>
+											{dataUpload
+												? dataUpload.filesTandaTerimaSS.map((e) => (
+													<tr>
+														<td>
+															<em className="fa-lg far fa-file-code"></em>
+														</td>
+														<td>
+															<a className="text-muted" href={e.preview} download={e.name}>
+																{e.name}
+															</a>
+														</td>
+													</tr>
+												))
+												: ""}
+										</tbody>
+									</table>
+								</Scrollable>
+							</Col>
+						</FormGroup>
+						<FormGroup row>
+							<Col md="4">Akhir Permohonan Keberatan Sanksi :</Col>
+							<Col md="8">
+								<strong>
+									{dataUpload && dataUpload.tglAkhirKeberatan ? (
+										<p>
+											{moment(dataUpload.tglAkhirKeberatan).locale("id").format("DD MMMM YYYY")}
+										</p>
+									) : (
+										""
+									)}
+								</strong>
+							</Col>
+						</FormGroup>
 					</form>
 				</Col>
 			</Row>

+ 299 - 0
components/Sanksi/SuratBA.js

@@ -0,0 +1,299 @@
+import React, { Component } from 'react';
+import SignatureCanvas from 'react-signature-canvas'
+import { getOneLaporan, updateLaporan } from "@/actions/pelaporan";
+import { Row, Col, Input, FormGroup, Label, Progress } from "reactstrap";
+import { connect } from "react-redux";
+import moment from "moment";
+import 'moment/locale/id'
+moment.locale('id')
+
+
+
+class ComponentToPrint extends React.Component {
+    formData = {}
+    constructor(props) {
+        super(props);
+        this.state = {
+            dataLaporan: {},
+            tempat: "[Mohon Diisi]",
+            isEditMode: false,
+            temuanLain: [],
+            memberatkan: [],
+            formData: null,
+            meringankan: [],
+            namaPeserta: [{ nama: "", ttd: [] }]
+        };
+    }
+
+    static getInitialProps = async ({ query }) => {
+        return { query };
+    };
+
+
+    componentDidMount = async () => {
+        const { query, token } = this.props;
+        const { id } = query;
+        const dataLaporan = await getOneLaporan(token, id);
+        this.setState({ dataLaporan });
+    };
+    changeEditMode = () => {
+        this.setState({
+            isEditMode: !this.state.isEditMode,
+        })
+    }
+    updateValueTempat = () => {
+        this.setState({
+            isEditMode: false,
+            tempat: this.refs.inputTempat.value
+        })
+    }
+    handleTemuanLain = (e) => {
+        const addTemuanLain = this.refs.inputTemuan.value
+        this.setState({
+            temuanLain: [...this.state.temuanLain, addTemuanLain]
+        }, this.setformData)
+    }
+    handleMemberatkan = (e) => {
+        const addMemberatkan = this.refs.inputMemberatkan.value
+        this.setState({
+            memberatkan: [...this.state.memberatkan, addMemberatkan]
+        }, this.setformData)
+    }
+    handleMeringankan = (e) => {
+        const addMeringankan = this.refs.inputMeringankan.value
+        this.setState({
+            meringankan: [...this.state.meringankan, addMeringankan]
+        }, this.setformData)
+    }
+    setNamaPeserta = () => {
+        const addNamaPeserta = this.refs.inputNama.value
+        this.setState({
+            namaPeserta: [...this.state.namaPeserta, addNamaPeserta]
+        })
+    }
+
+    setformData = (data) => {
+        this.setState({
+            formData: this.state
+        })
+    }
+
+
+
+    render() {
+        const { dataLaporan, tempat, isEditMode, temuanLain, formData, memberatkan, meringankan, namaPeserta } = this.state
+        const { dataPelanggaran } = this.props
+        return (
+            <div className='BA-div' >
+                <div className='BA-logo'>
+                    <img className='BA-logo' src="/static/img/logo-single-1-login.png" alt="logo" />
+                </div>
+                <div>
+                    <h3 className='BA-header'>LAPORAN HASIL EVALUASI DAN PEMBAHASAN</h3>
+                    {dataLaporan.data && (<h3 className='BA-header'>{dataLaporan.data.pt.nama}</h3>)}
+                    <div className='BA-body'>
+                        <p className='BA-body'>
+                            Pada hari ini <span>{moment(dataLaporan.createAt).locale("id").format("dddd")}</span>, tanggal&nbsp;{moment(dataLaporan.createAt).format("D")}&nbsp; bulan &nbsp;{moment(dataLaporan.createAt).format("MMMM")} tahun &nbsp;{moment(dataLaporan.createAt).format("YYYY")},
+                            bertempat di
+                            {isEditMode ?
+                                <span>
+                                    <input type='text'
+                                        defaultValue=""
+                                        ref="inputTempat" />
+                                    <button className='bg-transparent button-transparent border-0 fas fa-times-circle text-danger' onClick={this.changeEditMode} />
+                                    <button className='bg-transparent button-transparent border-0 fas fa-check-circle text-success' onClick={this.updateValueTempat} />
+                                </span>
+                                :
+                                <span color='danger' onClick={this.changeEditMode}>&nbsp;{tempat}</span>
+                            }
+                            ,
+                            telah dilakukan rapat evaluasi dan pembahasan dugaan pelanggaran penyelenggaraan oleh perguruan tinggi dan/atau badan penyelenggara {dataLaporan.data && (<span>{dataLaporan.data.pt.nama}</span>)}, yang dihadiri oleh:
+                        </p>
+                        <div className='BA-body'>
+                            <ol>
+                                <li contenteditable='true'>Isi name</li>
+                                <li contenteditable='true'>Isi nama</li>
+                                <li contenteditable='true'>Isi nama</li>
+                            </ol>
+                        </div>
+                    </div>
+                </div>
+                <div className='BA-body'>
+                    <p className='BA-body'>
+                        Berdasarkan rapat evaluasi dan pembahasan dugaan pelanggaran penyelenggaraan oleh perguruan tinggi dan/atau badan penyelenggara {dataLaporan.data && (<span>{dataLaporan.data.pt.nama}</span>)}, disampaikan sebagai berikut:
+                    </p>
+                    <div className='BA-body'>
+                        <ol>
+                            <li>Telah dibacakan Berita Acara Evaluasi Kinerja Perguruan Tinggi …….., tanggal ……..;</li>
+                            <li>Telah dilakukan pembahasan rekomendasi mengenai fakta-fakta yang ditemukan Tim EKPT Ditjen Diktiristek, dengan temuan sebagai berikut:</li>
+                            {/* <div style={{ overflow: "auto" }}> */}
+                            <table className='table-a'>
+                                <thead>
+                                    <tr>
+                                        <th rowspan="2">NO</th>
+                                        <th rowspan="2">NAMA DAN IZIN PRODI</th>
+                                        <th colspan="3">PELANGGARAN TERHADAP PERMENDIKBUD NO.7 TAHUN 2020</th>
+                                        <th rowspan="2">SIMPULAN</th>
+                                        <th rowspan="2">REKOMENDASI</th>
+                                    </tr>
+                                    <tr>
+                                        <th>PASAL</th>
+                                        <th>BUTIR PELANGGARAN</th>
+                                        <th>DESKRIPSI PELANGGARAN</th>
+                                    </tr>
+                                </thead>
+                                <tbody>
+                                    {dataPelanggaran
+                                        ? dataPelanggaran.map((e, i) => (
+                                            <tr key={e._id}>
+                                                <td>{++i}</td>
+                                                {dataLaporan.data && (<td className='BA-header'>{dataLaporan.data.pt.nama}</td>)}
+                                                <td>{e.pasal}</td>
+                                                <td>{e.butir_pelanggaran}</td>
+                                                <td>{e.pelanggaran}</td>
+                                                <td contenteditable='true'>[Mohon Diisi]</td>
+                                                <td contenteditable='true'>[Mohon Diisi]</td>
+                                            </tr>
+
+                                        ))
+                                        : ""}
+                                </tbody>
+                            </table>
+                            {/* </div> */}
+
+                            <li>Temuan Lain:
+                                {isEditMode ?
+                                    <span>
+                                        <input type='text' defaultValue={""} ref="inputTemuan" />
+                                        <button className='bg-transparent button-transparent border-0 fas fa-check-circle text-success' onClick={this.handleTemuanLain} />
+                                        <button className='bg-transparent button-transparent border-0 fas fa-times-circle text-danger' onClick={this.changeEditMode} />
+                                    </span>
+
+                                    : <span onClick={this.changeEditMode}>klik untuk isi</span>}
+                                <ol type="a">
+                                    {temuanLain.map((value) => <li>{value}</li>)}
+                                </ol>
+                            </li>
+                            <li>Hal-hal yang memberatkan, sebagai berikut:
+                                {isEditMode ?
+                                    <span>
+                                        <input type='text' defaultValue={""} ref="inputMemberatkan" />
+                                        <button className='bg-transparent button-transparent border-0 fas fa-check-circle text-success' onClick={this.handleMemberatkan} />
+                                        <button className='bg-transparent button-transparent border-0 fas fa-times-circle text-danger' onClick={this.changeEditMode} />
+                                    </span>
+
+                                    : <span onClick={this.changeEditMode}>klik untuk isi</span>}
+                                <ol type="a">
+                                    {memberatkan.map((value) => <li>{value}</li>)}
+                                </ol>
+                            </li>
+                            <li>hal-hal yang meringankan, sebagai berikut:
+                                {isEditMode ?
+                                    <span>
+                                        <input type='text' defaultValue={""} ref="inputMeringankan" />
+                                        <button className='bg-transparent button-transparent border-0 fas fa-check-circle text-success' onClick={this.handleMeringankan} />
+                                        <button className='bg-transparent button-transparent border-0 fas fa-times-circle text-danger' onClick={this.changeEditMode} />
+                                    </span>
+
+                                    : <span onClick={this.changeEditMode}>klik untuk isi</span>}
+                                <ol type="a">
+                                    {meringankan.map((value) => <li>{value}</li>)}
+                                </ol>
+                            </li>
+                            <li>
+                                Berdasarkan pembahasan yang dilakukan, disepakati untuk merekomendasikan <strong contenteditable='true'>“Sanksi Administratif berupa …………………………..”.</strong>
+                            </li>
+                        </ol>
+                    </div>
+                    <p className='BA-body'>
+                        Demikian Laporan Evaluasi dan Pembahasan ini dibuat dengan sesungguhnya dan telah dibaca dan dicermati oleh peserta rapat yang hadir.
+                    </p>
+                    <table className='demo'>
+                        <tbody>
+                            <tr>
+                                <th colspan="4">PESERTA RAPAT PENYUSUNAN REKOMENDASI</th>
+                            </tr>
+                            <tr>
+                                <td contenteditable='true' onChange={this.setNamaPeserta} ref="inputNama">Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                                <td contenteditable='true'>Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                            </tr>
+                            <tr>
+                                <td contenteditable='true'>Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                                <td contenteditable='true'>Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                            </tr>
+                            <tr>
+                                <td contenteditable='true'>Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                                <td contenteditable='true'>Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                            </tr>
+                            <tr>
+                                <td contenteditable='true'>Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                                <td contenteditable='true'>Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                            </tr>
+                            <tr>
+                                <td contenteditable='true'>Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                                <td contenteditable='true'>Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                            </tr>
+                            <tr>
+                                <td contenteditable='true'>Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                                <td contenteditable='true'>Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                            </tr>
+                            <tr>
+                                <td contenteditable='true'>Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                                <td contenteditable='true'>Isi Nama</td>
+                                <td>
+                                    <SignatureCanvas penColor='black' canvasProps={{ width: 200, height: 100, className: 'sigCanvas' }} />
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+                <div id="footer">
+                    <span>*LAPORAN HASIL EVALUASI DAN PEMBAHASAN …………. – …bulan&tahun…</span>
+                    {/* <span class="custom-footer-page-number">Number: </span> */}
+                </div>
+
+            </div>
+
+        );
+    }
+}
+export default ComponentToPrint

+ 40 - 2
components/Sanksi/TablePenetapanSanksi.js

@@ -2,6 +2,12 @@ import React, { Component } from "react";
 import { Card, Table } from "reactstrap";
 import { getPelanggaran } from "@/actions/pelanggaran";
 import { connect } from "react-redux";
+import Button from "reactstrap/lib/Button";
+import { getOneLaporan, updateLaporan } from "@/actions/pelaporan";
+import Router from "next/router";
+import { ToastContainer, toast } from "react-toastify";
+
+
 
 export class TablePenetapanSanksi extends Component {
 	checkedData = [];
@@ -11,6 +17,9 @@ export class TablePenetapanSanksi extends Component {
 		this.state = {
 			pelanggaran: null,
 			checkedData: [],
+			labelSanksi: [],
+			btnDelegasi: false,
+
 		};
 	}
 
@@ -28,8 +37,20 @@ export class TablePenetapanSanksi extends Component {
 		this.props.setCheckedData(this.checkedData);
 	};
 
+	setLabelSanksi = (evt, label_sanksi) => {
+		const checked = evt.target.checked;
+		const item = evt.target.value;
+		if (checked) this.state.labelSanksi.push({ value: item, labelSanksi: label_sanksi });
+		else this.state.labelSanksi = this.state.labelSanksi.filter((e) => e.value != item);
+	}
+
+	ondelegasi = () => {
+		this.props.handleDelegasi(this.state)
+	}
+
 	render() {
-		const { pelanggaran } = this.state;
+		const { pelanggaran, labelSanksi, checkedData } = this.state;
+
 		return (
 			<Card className="card-default">
 				<Table bordered hover responsive>
@@ -72,7 +93,10 @@ export class TablePenetapanSanksi extends Component {
 									<td>
 										<div className="checkbox c-checkbox">
 											<label>
-												<input type="checkbox" value={jp._id} onChange={this.onHandleChange} />
+												<input type="checkbox" value={jp._id} onChange={(evt) => {
+													this.onHandleChange(evt)
+													this.setLabelSanksi(evt, jp.label_sanksi)
+												}} />
 												<span className="fa fa-check"></span>
 											</label>
 										</div>
@@ -82,6 +106,20 @@ export class TablePenetapanSanksi extends Component {
 							: ""}
 					</tbody>
 				</Table>
+				<div className="float-right m-2 ">
+					{
+						labelSanksi.filter((e) => e.labelSanksi === "Ringan").length === labelSanksi.length ? (
+							<Button className="btn-login float-right" color onClick={this.ondelegasi} >
+								<span className="font-color-white">
+									Delegasi ke LLDIKTI
+								</span>
+							</Button>
+						) : ("")
+
+
+					}
+				</div>
+
 			</Card>
 		);
 	}

+ 211 - 5
components/Sanksi/UploadSurat.js

@@ -5,10 +5,10 @@ import DatePicker from "react-datepicker";
 import "react-datepicker/dist/react-datepicker.css";
 // import "react-datepicker/dist/react-datepicker.css";
 import ms from "ms";
-import TmtDate from "./TmtDate";
 import { addDays, addMonths } from 'date-fns';
 import id from 'date-fns/locale/id';
 // registerLocale('id', id)
+import { getAutoSave, inputAutoSave } from "@/actions/autosave";
 
 let Dropzone = null;
 class DropzoneWrapper extends Component {
@@ -82,6 +82,12 @@ export class UploadSurat extends Component {
 			awalsanksi: "",
 			akhirsanksi: "",
 			tmtCheck: false,
+			filesBeritaAcara: [],
+			saveData: [],
+			terimaSuratSanksi: "",
+			tglAkhirKeberatan: "",
+			filesTandaTerimaSS: [],
+
 		};
 	}
 
@@ -97,6 +103,45 @@ export class UploadSurat extends Component {
 		this.props.setUploadSuratSanksi(this.state);
 	};
 
+	onDropBA = (filesBeritaAcara) => {
+		this.setState({
+			filesBeritaAcara: filesBeritaAcara.map((file) =>
+				Object.assign(file, {
+					preview: URL.createObjectURL(file),
+				})
+			),
+			stat: "Added " + filesBeritaAcara.length + " file(s)",
+		});
+		this.props.setUploadSuratSanksi(this.state);
+	};
+	onDropTandaTerimaSS = (filesTandaTerimaSS) => {
+		this.setState({
+			filesTandaTerimaSS: filesTandaTerimaSS.map((file) =>
+				Object.assign(file, {
+					preview: URL.createObjectURL(file),
+				})
+			),
+			stat: "Added " + filesTandaTerimaSS.length + " file(s)",
+		});
+		this.props.setUploadSuratSanksi(this.state);
+	};
+
+	componentDidMount = async () => {
+		const { query, token } = this.props;
+		const { id } = query;
+		const getDataSave = await getAutoSave({ token, id, laporan: true });
+		const saveData = getDataSave.data?.penetapanSanksi;
+		this.setState(saveData)
+	}
+
+	handleAutoSave = async () => {
+		const { query, token } = this.props;
+		const { id } = query;
+		const { nomorSanksi, keterangan } = this.state
+		const saveData = await inputAutoSave({ data: { penetapanSanksi: { nomorSanksi, keterangan } }, token, id, laporan: true })
+
+	}
+
 	uploadFiles = (e) => {
 		e.preventDefault();
 		e.stopPropagation();
@@ -111,9 +156,33 @@ export class UploadSurat extends Component {
 		e.stopPropagation();
 		this.setState({
 			stat: this.state.files.length ? this.state.files.length + " file(s) cleared." : "No files to clear.",
+			stat: this.state.filesBeritaAcara.length ? this.state.filesBeritaAcara.length + " file(s) cleared." : "No files to clear.",
 		});
 		this.setState({
 			files: [],
+			filesBeritaAcara: [],
+		});
+		this.props.setUploadSuratSanksi(this.state);
+	};
+	clearFilesBA = (e) => {
+		e.preventDefault();
+		e.stopPropagation();
+		this.setState({
+			stat: this.state.filesBeritaAcara.length ? this.state.filesBeritaAcara.length + " file(s) cleared." : "No files to clear.",
+		});
+		this.setState({
+			filesBeritaAcara: [],
+		});
+		this.props.setUploadSuratSanksi(this.state);
+	};
+	clearFilesTerimaSanksi = (e) => {
+		e.preventDefault();
+		e.stopPropagation();
+		this.setState({
+			stat: this.state.filesTandaTerimaSS.length ? this.state.filesTandaTerimaSS.length + " file(s) cleared." : "No files to clear.",
+		});
+		this.setState({
+			filesTandaTerimaSS: [],
 		});
 		this.props.setUploadSuratSanksi(this.state);
 	};
@@ -140,8 +209,7 @@ export class UploadSurat extends Component {
 		this.setState({ tmtCheck: !this.state.tmtCheck }, this.toRingkasan);
 	}
 	render() {
-		const { files } = this.state;
-
+		const { files, filesBeritaAcara, terimaSuratSanksi, tglAkhirKeberatan, filesTandaTerimaSS, tmtCheck } = this.state;
 		const removeFile = file => () => {
 			const newFiles = [...files]
 			newFiles.splice(newFiles.indexOf(file), 1)
@@ -149,24 +217,50 @@ export class UploadSurat extends Component {
 				files: newFiles,
 			});
 		}
+		const removeFileBA = file => () => {
+			const newFiles = [...filesBeritaAcara]
+			newFiles.splice(newFiles.indexOf(file), 1)
+			this.setState({
+				filesBeritaAcara: newFiles,
+			});
+		}
+		const removeFileTandaTerimaSS = file => () => {
+			const newFiles = [...filesTandaTerimaSS]
+			newFiles.splice(newFiles.indexOf(file), 1)
+			this.setState({
+				filesTandaTerimaSS: newFiles,
+			});
+		}
 		const thumbs = files.map((file, index) => (
 			<p>
 				<em className="far fa-file" />&nbsp;&nbsp;{file.name}
 				<button className="bg-transparent button-transparent border-0 fas fa-trash text-danger float-right" onClick={removeFile(file)} />
 			</p>
 		));
+		const thumbsBA = filesBeritaAcara.map((file, index) => (
+			<p>
+				<em className="far fa-file" />&nbsp;&nbsp;{file.name}
+				<button className="bg-transparent button-transparent border-0 fas fa-trash text-danger float-right" onClick={removeFileBA(file)} />
+			</p>
+		));
+		const thumbsTandaTerimaSS = filesTandaTerimaSS.map((file, index) => (
+			<p>
+				<em className="far fa-file" />&nbsp;&nbsp;{file.name}
+				<button className="bg-transparent button-transparent border-0 fas fa-trash text-danger float-right" onClick={removeFileTandaTerimaSS(file)} />
+			</p>
+		));
 		return (
 			<form className="form-horizontal" method="get" action="/" onSubmit={this.onSubmit}>
 				<FormGroup row>
 					<label className="col-md-2 col-form-label">Nomor Surat:</label>
 					<div className="col-md-10">
-						<Input type="text" value={this.state.nomorSanksi} onChange={this.setNomorSanksi} />
+						<Input type="text" value={this.state.nomorSanksi} onChange={(e) => { this.setNomorSanksi(e); this.handleAutoSave() }} />
 					</div>
 				</FormGroup>
 				<FormGroup row className="mt-3">
 					<label className="col-md-2 col-form-label">Keterangan</label>
 					<div className="col-md-10">
-						<Input type="textarea" value={this.state.keterangan} onChange={this.setKeterangan} required />
+						<Input type="textarea" value={this.state.keterangan} onChange={(e) => { this.setKeterangan(e); this.handleAutoSave() }} required />
 					</div>
 				</FormGroup>
 				<FormGroup row>
@@ -309,6 +403,118 @@ export class UploadSurat extends Component {
 						<p className="mrgn-top-5 font-color-black">Ukuran setiap dokumen maksimal 15mb</p>
 					</div>
 				</FormGroup>
+				<FormGroup row>
+					<label className="col-md-2 col-form-label">
+						Dokumen Laporan Evaluasi dan Pembahasan<span>: &nbsp;</span><span className="text-danger">*</span>
+					</label>
+					<div className="col-md-10">
+						<DropzoneWrapper className="" onDrop={this.onDropBA}>
+							{({ getRootProps, getInputProps, isDragActive }) => {
+								return (
+									<div {...getRootProps()} className={"dropzone card" + (isDragActive ? "dropzone-drag-active" : "")}>
+										<input {...getInputProps()} />
+										<div className="dropzone-style-1">
+											<div className="center-ver-hor dropzone-previews flex">
+												{this.state.filesBeritaAcara.length > 0 ? (
+													<div className="text-center fa-2x icon-cloud-upload mr-2 ">
+														<h5 className="text-center dz-default dz-message">Klik untuk tambah file</h5>
+													</div>
+												) : (
+													<div className="text-center fa-2x icon-cloud-upload mr-2 ">
+														<h5 className="text-center dz-default dz-message">Klik untuk upload dokumen</h5>
+													</div>
+												)}
+											</div>
+										</div>
+										<div className="d-flex align-items-center">
+											<small className="ml-auto">
+												<button type="button" className="btn btn-link" onClick={this.clearFilesBA}>
+													Reset dokumen
+												</button>
+											</small>
+										</div>
+									</div>
+								);
+							}}
+						</DropzoneWrapper>
+						<div>
+							{thumbsBA}
+						</div>
+						<p className="mrgn-top-5 font-color-black">Ukuran setiap dokumen maksimal 15mb</p>
+					</div>
+				</FormGroup>
+				<FormGroup row className="mt-3">
+					<label className="col-md-2 col-form-label">Tanggal Terima Surat Sanksi</label>
+					<span className="col-sm-3 float-left">
+						<DatePicker
+							selected={terimaSuratSanksi}
+							onChange={(terimaSuratSanksi) => {
+								this.setState({ terimaSuratSanksi }, this.toRingkasan)
+							}}
+							dateFormat="dd/MM/yyyy"
+							minDate={this.state.awalsanksi}
+							placeholderText="Isi Tanggal"
+							locale={id}
+							className="form-control bg-white"
+						/>
+					</span>
+				</FormGroup>
+				<FormGroup row>
+					<label className="col-md-2 col-form-label">
+						Dokumen Tanda Terima Surat Sanksi<span>: &nbsp;</span><span className="text-danger">*</span>
+					</label>
+					<div className="col-md-10">
+						<DropzoneWrapper className="" onDrop={this.onDropTandaTerimaSS}>
+							{({ getRootProps, getInputProps, isDragActive }) => {
+								return (
+									<div {...getRootProps()} className={"dropzone card" + (isDragActive ? "dropzone-drag-active" : "")}>
+										<input {...getInputProps()} />
+										<div className="dropzone-style-1">
+											<div className="center-ver-hor dropzone-previews flex">
+												{this.state.filesBeritaAcara.length > 0 ? (
+													<div className="text-center fa-2x icon-cloud-upload mr-2 ">
+														<h5 className="text-center dz-default dz-message">Klik untuk tambah file</h5>
+													</div>
+												) : (
+													<div className="text-center fa-2x icon-cloud-upload mr-2 ">
+														<h5 className="text-center dz-default dz-message">Klik untuk upload dokumen</h5>
+													</div>
+												)}
+											</div>
+										</div>
+										<div className="d-flex align-items-center">
+											<small className="ml-auto">
+												<button type="button" className="btn btn-link" onClick={this.clearFilesTerimaSanksi}>
+													Reset dokumen
+												</button>
+											</small>
+										</div>
+									</div>
+								);
+							}}
+						</DropzoneWrapper>
+						<div>
+							{thumbsTandaTerimaSS}
+						</div>
+						<p className="mrgn-top-5 font-color-black">Ukuran setiap dokumen maksimal 15mb</p>
+					</div>
+				</FormGroup>
+				<FormGroup row className="mt-3">
+					<label className="col-md-2 col-form-label">Akhir Permohonan Keberatan Sanksi</label>
+					<span className="col-sm-3 float-left">
+						<DatePicker
+							selected={tglAkhirKeberatan}
+							onChange={(tglAkhirKeberatan) => {
+								this.setState({ tglAkhirKeberatan }, this.toRingkasan)
+							}}
+							dateFormat="dd/MM/yyyy"
+							minDate={terimaSuratSanksi}
+							placeholderText="Isi Tanggal"
+							locale={id}
+							className="form-control bg-white"
+						/>
+					</span>
+				</FormGroup>
 			</form >
 		);
 	}

+ 11 - 0
components/TurunSanksi/TableLaporan.js

@@ -15,6 +15,7 @@ function TableLaporan({ listData, to, linkName, status = false, noBy = false })
 							<thead>
 								<tr>
 									<th>No.Laporan</th>
+									<th>No.Sanksi</th>
 									<th>Deskripsi Laporan</th>
 									{<th>TMT Berlaku</th>}
 									{/* {!noBy && <th>Dibuat Oleh</th>} */}
@@ -37,6 +38,16 @@ function TableLaporan({ listData, to, linkName, status = false, noBy = false })
 													</div>
 												</div>
 											</td>
+											<td>
+												{/* <td>{data.no_laporan}</td> */}
+												<div className="media align-items-center">
+													<div className="media-body d-flex">
+														<div>
+															<h4>{data.no_sanksi}</h4>
+														</div>
+													</div>
+												</div>
+											</td>
 
 											<td>
 												<div className="table-desc">

+ 39 - 0
package-lock.json

@@ -9210,6 +9210,15 @@
         }
       }
     },
+    "react-signature-canvas": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/react-signature-canvas/-/react-signature-canvas-1.0.6.tgz",
+      "integrity": "sha512-NoMHomYu9HxFeLjUGbIeV9abPdWSROfFxFNDekGdwmmaIx+w5ziOEiU2C34X0Ao4GxFnwqyUy/BpYlA4lCD1CA==",
+      "requires": {
+        "signature_pad": "^2.3.2",
+        "trim-canvas": "^0.1.0"
+      }
+    },
     "react-sticky": {
       "version": "6.0.3",
       "resolved": "https://registry.npmjs.org/react-sticky/-/react-sticky-6.0.3.tgz",
@@ -9219,6 +9228,26 @@
         "raf": "^3.3.0"
       }
     },
+    "react-to-print": {
+      "version": "2.14.11",
+      "resolved": "https://registry.npmjs.org/react-to-print/-/react-to-print-2.14.11.tgz",
+      "integrity": "sha512-sePHBaCtZLp8/g4d/gRyI9XQZkveZq6xoukanAHfkzlXOa7sTuXCEQOYq37lIa5MkUoxySdJxYuyClaXPa9Zpg==",
+      "requires": {
+        "prop-types": "^15.8.1"
+      },
+      "dependencies": {
+        "prop-types": {
+          "version": "15.8.1",
+          "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+          "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+          "requires": {
+            "loose-envify": "^1.4.0",
+            "object-assign": "^4.1.1",
+            "react-is": "^16.13.1"
+          }
+        }
+      }
+    },
     "react-toastify": {
       "version": "8.2.0",
       "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-8.2.0.tgz",
@@ -10055,6 +10084,11 @@
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
       "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
     },
+    "signature_pad": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/signature_pad/-/signature_pad-2.3.2.tgz",
+      "integrity": "sha512-peYXLxOsIY6MES2TrRLDiNg2T++8gGbpP2yaC+6Ohtxr+a2dzoaqWosWDY9sWqTAAk6E/TyQO+LJw9zQwyu5kA=="
+    },
     "simple-concat": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
@@ -10991,6 +11025,11 @@
       "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz",
       "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc="
     },
+    "trim-canvas": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/trim-canvas/-/trim-canvas-0.1.2.tgz",
+      "integrity": "sha512-nd4Ga3iLFV94mdhW9JFMLpQbHUyCQuhFOD71PEAt1NjtMD5wbZctzhX8c3agHNybMR5zXD1XTGoIEWk995E6pQ=="
+    },
     "trim-newlines": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",

+ 2 - 0
package.json

@@ -99,7 +99,9 @@
     "react-perfect-scrollbar": "1.5.8",
     "react-redux": "^7.2.6",
     "react-select": "^3.0.4",
+    "react-signature-canvas": "^1.0.6",
     "react-sticky": "^6.0.3",
+    "react-to-print": "^2.14.11",
     "react-toastify": "8.2.0",
     "react-transition-group": "4.2.2",
     "reactstrap": "^8.0.1",

+ 180 - 4
pages/app/banding/detail.js

@@ -10,7 +10,7 @@ import Riwayat from "@/components/Banding/Riwayat";
 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 { Row, Col, Card, CardBody, FormGroup, Button, Modal, ModalHeader, ModalBody, ModalFooter, Input } from "reactstrap";
 import { getPT } from "@/actions/PT";
 import Loader from "@/components/Common/Loader";
 import { toast } from "react-toastify";
@@ -18,6 +18,11 @@ import { connect } from "react-redux";
 import { Formik, Form, Field, ErrorMessage } from "formik";
 import * as Yup from "yup";
 import { createLog } from "@/actions/log";
+import DatePicker from "react-datepicker";
+import "react-datepicker/dist/react-datepicker.css";
+import id from 'date-fns/locale/id';
+import moment from "moment";
+import Datetime from "react-datetime";
 
 let Dropzone = null;
 class DropzoneWrapper extends Component {
@@ -61,6 +66,11 @@ const checkIfFilesAreCorrectType = (files) => {
 const jawabanBandingSchema = Yup.object().shape({
 	status: Yup.string().required("Harap Diisi"),
 	dokumen: Yup.array().min(1, "Minimal terdapat 1 dokumen").required("Required").test("filesize", "Maksimal ukuran dokumen 15mb", checkIfFilesAreTooBig),
+	keterangan: Yup.string().min(3).max(200).required("Harap Diisi"),
+	dokumen_terima_banding: Yup.array().notRequired().test("filesize", "Maksimal ukuran dokumen 15mb", checkIfFilesAreTooBig),
+	tanggal_terima_banding: Yup.string().notRequired("Wajib diisi"),
+	no_banding: Yup.string().min(3).notRequired("Harap Diisi"),
+	tanggal_surat_banding: Yup.string().notRequired("Wajib diisi"),
 });
 class JawabanBanding extends Component {
 	constructor(props) {
@@ -71,6 +81,11 @@ class JawabanBanding extends Component {
 			files: [],
 			sanksi: {},
 			pt: null,
+			fileDocTerimaBanding: [],
+			no_banding: "",
+			tglTerimaBanding: "",
+			keterangan: "",
+			tglSuratBanding: "",
 		};
 	}
 
@@ -106,6 +121,16 @@ class JawabanBanding extends Component {
 			stat: "Added " + files.length + " file(s)",
 		});
 	};
+	onDropDocTerimaBanding = (fileDocTerimaBanding) => {
+		this.setState({
+			fileDocTerimaBanding: fileDocTerimaBanding.map((file) =>
+				Object.assign(file, {
+					preview: URL.createObjectURL(file),
+				})
+			),
+			stat: "Added " + fileDocTerimaBanding.length + " file(s)",
+		});
+	};
 
 	uploadFiles = (e) => {
 		e.preventDefault();
@@ -125,6 +150,18 @@ class JawabanBanding extends Component {
 			files: [],
 		});
 	};
+	clearFilesDocTerimaBandig = (e) => {
+		e.preventDefault();
+		e.stopPropagation();
+		this.setState({
+			stat: this.state.fileDocTerimaBanding.length ? this.state.fileDocTerimaBanding.length + " file(s) cleared." : "No files to clear.",
+		});
+		this.setState({
+			fileDocTerimaBanding: [],
+		});
+	};
+
+
 
 	handelSimpan = async () => {
 		if (this.state.modal === true) {
@@ -135,9 +172,16 @@ class JawabanBanding extends Component {
 		const { id } = query;
 		const formdata = new FormData();
 		formdata.append("status", data.status);
+		formdata.append("keterangan", data.keterangan);
+		formdata.append("no_banding", data.no_banding);
+		formdata.append("tanggal_terima_banding", data.tanggal_terima_banding);
+		formdata.append("tanggal_surat_banding", data.tanggal_surat_banding);
 		data.dokumen.forEach((e) => {
 			formdata.append("dokumen", e);
 		});
+		data.dokumen_terima_banding.forEach((e) => {
+			formdata.append("dokumen_terima_banding", e);
+		});
 		const toastid = toast.loading("Please wait...");
 		const added = await addJawabanBanding(token, id, formdata);
 		if (!added) {
@@ -150,8 +194,15 @@ class JawabanBanding extends Component {
 		}
 	};
 
+	setTglTerimaBanding = (tglTerimaBanding) => {
+		this.setState({ tglTerimaBanding })
+	}
+	setTglSuratBanding = (tglSuratBanding) => {
+		this.setState({ tglSuratBanding })
+	}
+
 	render() {
-		const { files, sanksi, pt } = this.state;
+		const { files, sanksi, pt, fileDocTerimaBanding, tglSuratBanding, tglTerimaBanding } = this.state;
 
 		const thumbs = files.map((file, index) => (
 			<div md={3} key={index}>
@@ -160,6 +211,13 @@ class JawabanBanding extends Component {
 			</div>
 		));
 
+		const thumbsDocTerimaBanding = fileDocTerimaBanding.map((file, index) => (
+			<div md={3} key={index}>
+				{/* <img className="img-fluid mb-2" src={file.preview} alt="Item" /> */}
+				<span className="text-left">{index + 1}.{file.name}</span>
+			</div>
+		));
+
 		return (
 			<ContentWrapper unwrap>
 				{/* <Header /> */}
@@ -187,7 +245,12 @@ class JawabanBanding extends Component {
 												<Formik
 													initialValues={{
 														status: "",
+														keterangan: "",
 														dokumen: [],
+														tanggal_terima_banding: "",
+														no_banding: "",
+														dokumen_terima_banding: [],
+														tanggal_surat_banding: ""
 													}}
 													validationSchema={jawabanBandingSchema}
 													onSubmit={async (data) => {
@@ -221,7 +284,44 @@ class JawabanBanding extends Component {
 																</div>
 															</FormGroup>
 															<FormGroup>
-																<label className="row-form-label">Dokumen Jawaban<span className="text-danger">*</span>:</label>
+																<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">Nomor Surat Jawaban Atas Permohonan Banding:</label>
+																<div className="row-md-10">
+																	<Field name="no_banding">{({ field }) => <Input type="text" {...field} />}</Field>
+																	<ErrorMessage name="no_banding" component="div" className="form-text text-danger" />
+																</div>
+															</FormGroup>
+															<FormGroup>
+																<label className="row-form-label">Tanggal Surat Jawaban Atas Permohonan Banding :</label>
+																<div className="row-md-10">
+																	<Field name="tanggal_terima_banding">
+																		{({ field, form }) => (
+
+																			<DatePicker
+																				selected={this.state.tglTerimaBanding || field.value}
+																				onChange={(e) => {
+																					form.setFieldValue(field.name, e);
+																					this.setTglTerimaBanding(e)
+																				}}
+																				dateFormat="dd/MM/yyyy"
+																				placeholderText="Isi Tanggal"
+																				locale={id}
+																				className="form-control bg-white"
+																			/>
+																		)}
+																	</Field>
+																	<ErrorMessage name="tanggal_terima_banding" component="div" className="form-text text-danger" />
+																</div>
+															</FormGroup>
+															<FormGroup>
+																<label className="row-form-label">Dokumen Jawaban Atas Permohonan Banding:</label>
 																<div className="row-md-10">
 																	<Field name="dokumen">
 																		{({ field, form }) => (
@@ -244,7 +344,8 @@ class JawabanBanding extends Component {
 																										</div>
 																									}
 																									</div>
-																								</div>																							</div>
+																								</div>
+																							</div>
 																							<div className="d-flex align-items-center">
 																								<small className="ml-auto">
 																									<button
@@ -269,6 +370,81 @@ class JawabanBanding extends Component {
 																	<p className="mrgn-top-5">Ukuran setiap dokumen maksimal 15mb</p>
 																</div>
 															</FormGroup>
+
+															<FormGroup>
+																<label className="row-form-label">Tanda Terima Surat Jawaban Permohonan Banding<span className="star-color">*</span> :</label>
+																<div className="row-md-10">
+																	<Field name="tanggal_surat_banding">
+																		{({ field, form }) => (
+
+																			<DatePicker
+																				selected={this.state.tglSuratBanding || field.value}
+																				onChange={(e) => {
+																					form.setFieldValue(field.name, e);
+																					this.setTglSuratBanding(e)
+																				}}
+																				minDate={tglTerimaBanding}
+																				dateFormat="dd/MM/yyyy"
+																				placeholderText="Isi Tanggal"
+																				locale={id}
+																				className="form-control bg-white"
+																			/>
+																		)}
+																	</Field>
+																	<ErrorMessage name="tanggal_surat_banding" component="div" className="form-text text-danger" />
+																</div>
+															</FormGroup>
+
+															<FormGroup>
+																<label className="row-form-label">Dokumen Tanda Terima Surat Jawaban Permohonan banding<span className="star-color">*</span>:</label>
+																<div className="row-md-10">
+																	<Field name="dokumen_terima_banding">
+																		{({ field, form }) => (
+																			<DropzoneWrapper
+																				className=""
+																				onDrop={(e) => {
+																					this.onDropDocTerimaBanding(e);
+																					form.setFieldValue(field.name, e);
+																				}}
+																			>
+																				{({ getRootProps, getInputProps, isDragActive }) => {
+																					return (
+																						<div {...getRootProps()} className={"dropzone card" + (isDragActive ? "dropzone-drag-active" : "")}>
+																							<input {...getInputProps()} />
+																							<div className="dropzone-previews flex">
+																								<div className="dropzone-style-1">
+																									<div className="center-ver-hor dropzone-previews flex">{this.state.fileDocTerimaBanding.length > 0 ? <Row><span className="text-left">{thumbsDocTerimaBanding}</span></Row> :
+																										<div className="text-center fa-2x icon-cloud-upload mr-2 ">
+																											<h5 className="text-center dz-default dz-message">Klik untuk upload dokumen</h5>
+																										</div>
+																									}
+																									</div>
+																								</div>
+																							</div>
+																							<div className="d-flex align-items-center">
+																								<small className="ml-auto">
+																									<button
+																										type="button"
+																										className="btn btn-link"
+																										onClick={(e) => {
+																											this.clearFilesDocTerimaBandig(e);
+																											form.setFieldValue(field.name, []);
+																										}}
+																									>
+																										Reset dokumen
+																									</button>
+																								</small>
+																							</div>
+																						</div>
+																					);
+																				}}
+																			</DropzoneWrapper>
+																		)}
+																	</Field>
+																	<ErrorMessage name="dokumen_terima_banding" component="div" className="form-text text-danger" />
+																	<p className="mrgn-top-5">Ukuran setiap dokumen maksimal 15mb</p>
+																</div>
+															</FormGroup>
 															<FormGroup row>
 																<div className="col-xl-10">
 																	<Button color className="color-3e3a8e btn-login" type="submit">

+ 1 - 1
pages/app/index.js

@@ -112,7 +112,7 @@ class App extends Component {
               </Col>
             </Row>
           </Jumbotron>
-          <span>Version 2.2 ~ 1.96</span>
+          <span>Version 2.13 ~ 2.12</span>
         </ContentWrapper>
       </div>
     );

+ 191 - 12
pages/app/keberatan/detail.js

@@ -18,6 +18,12 @@ import { connect } from "react-redux";
 import { Formik, Form, Field, ErrorMessage } from "formik";
 import * as Yup from "yup";
 import { createLog } from "@/actions/log";
+import DatePicker from "react-datepicker";
+import "react-datepicker/dist/react-datepicker.css";
+import id from 'date-fns/locale/id';
+import moment from "moment";
+import Datetime from "react-datetime";
+
 
 let Dropzone = null;
 class DropzoneWrapper extends Component {
@@ -63,6 +69,11 @@ const jawabanKeberatanSchema = Yup.object().shape({
 	status: Yup.string().required("Harap Diisi"),
 	keterangan: Yup.string().min(3).max(200).required("Harap Diisi"),
 	dokumen: Yup.array().notRequired().test("filesize", "Maksimal ukuran dokumen 15mb", checkIfFilesAreTooBig),
+	dokumen_terima_keberatan: Yup.array().notRequired().test("filesize", "Maksimal ukuran dokumen 15mb", checkIfFilesAreTooBig),
+	tanggal_terima_keberatan: Yup.string().notRequired("Wajib diisi"),
+	no_keberatan: Yup.string().min(3).notRequired("Harap Diisi"),
+	tanggal_akhir_banding: Yup.string().notRequired("Wajib diisi"),
+	tanggal_surat_keberatan: Yup.string().notRequired("Wajib diisi"),
 });
 class DetailKeberatan extends Component {
 	constructor(props) {
@@ -71,10 +82,15 @@ class DetailKeberatan extends Component {
 			modal: false,
 			selectedOption: null,
 			files: [],
+			fileTTSKeberatan: [],
+			no_keberatan: "",
+			tglTerimaKeberatan: "",
+			tglAkhirBanding: "",
 			keterangan: "",
 			sanksi: {},
 			pt: null,
 			data: {},
+			tglSuratKeberatan: "",
 		};
 	}
 
@@ -110,6 +126,16 @@ class DetailKeberatan extends Component {
 			stat: "Added " + files.length + " file(s)",
 		});
 	};
+	onDropTTSKeberatan = (fileTTSKeberatan) => {
+		this.setState({
+			fileTTSKeberatan: fileTTSKeberatan.map((file) =>
+				Object.assign(file, {
+					preview: URL.createObjectURL(file),
+				})
+			),
+			stat: "Added " + fileTTSKeberatan.length + " file(s)",
+		});
+	};
 
 	uploadFiles = (e) => {
 		e.preventDefault();
@@ -129,6 +155,16 @@ class DetailKeberatan extends Component {
 			files: [],
 		});
 	};
+	clearFilesTTSKeberatan = (e) => {
+		e.preventDefault();
+		e.stopPropagation();
+		this.setState({
+			stat: this.state.fileTTSKeberatan.length ? this.state.fileTTSKeberatan.length + " file(s) cleared." : "No files to clear.",
+		});
+		this.setState({
+			fileTTSKeberatan: [],
+		});
+	};
 
 	handelSimpan = async () => {
 		if (this.state.modal === true) {
@@ -140,9 +176,16 @@ class DetailKeberatan extends Component {
 		const formdata = new FormData();
 		formdata.append("keterangan", data.keterangan);
 		formdata.append("status", data.status);
+		formdata.append("no_keberatan", data.no_keberatan);
+		formdata.append("tanggal_terima_keberatan", data.tanggal_terima_keberatan);
+		formdata.append("tanggal_akhir_banding", data.tanggal_akhir_banding);
+		formdata.append("tanggal_surat_keberatan", data.tanggal_surat_keberatan);
 		data.dokumen.forEach((e) => {
 			formdata.append("dokumen", e);
 		});
+		data.dokumen_terima_keberatan.forEach((e) => {
+			formdata.append("dokumen_terima_keberatan", e);
+		});
 		const toastid = toast.loading("Please wait...");
 		const added = await addJawabanKeberatan(token, id, formdata);
 		if (!added) {
@@ -154,17 +197,27 @@ class DetailKeberatan extends Component {
 			});
 		}
 	};
+	setTglTerimaKeberatan = (tglTerimaKeberatan) => {
+		this.setState({ tglTerimaKeberatan })
+	}
+	setTglSuratKeberatan = (tglSuratKeberatan) => {
+		this.setState({ tglSuratKeberatan })
+	}
 
 	render() {
-		const { files, sanksi, pt } = this.state;
-
+		const { files, sanksi, pt, fileTTSKeberatan, tglTerimaKeberatan, tglSuratKeberatan } = this.state;
 		const thumbs = files.map((file, index) => (
 			<div md={3} key={index}>
 				{/* <img className="img-fluid mb-2" src={file.preview} alt="Item" /> */}
 				<span className="text-left">{index + 1}.{file.name}</span>
 			</div>
 		));
-
+		const thumbsTTSKeberatan = fileTTSKeberatan.map((file, index) => (
+			<div md={3} key={index}>
+				{/* <img className="img-fluid mb-2" src={file.preview} alt="Item" /> */}
+				<span className="text-left">{index + 1}.{file.name}</span>
+			</div>
+		));
 		return (
 			<ContentWrapper unwrap>
 				{/* <Header /> */}
@@ -202,6 +255,12 @@ class DetailKeberatan extends Component {
 														status: "",
 														keterangan: "",
 														dokumen: [],
+														tanggal_terima_keberatan: "",
+														no_keberatan: "",
+														dokumen_terima_keberatan: [],
+														tanggal_akhir_banding: "",
+														tanggal_surat_keberatan: ""
+
 													}}
 													validationSchema={jawabanKeberatanSchema}
 													onSubmit={async (data) => {
@@ -236,7 +295,7 @@ class DetailKeberatan extends Component {
 																</div>
 															</FormGroup>
 															<FormGroup>
-																<label className="row-form-label">Keterangan Jawaban:</label>
+																<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" />
@@ -244,7 +303,36 @@ class DetailKeberatan extends Component {
 																</div>
 															</FormGroup>
 															<FormGroup>
-																<label className="row-form-label">Dokumen Jawaban:</label>
+																<label className="row-form-label">Nomor Surat Jawaban Atas Permohonan Keberatan:</label>
+																<div className="row-md-10">
+																	<Field name="no_keberatan">{({ field }) => <Input type="text" {...field} />}</Field>
+																	<ErrorMessage name="no_keberatan" component="div" className="form-text text-danger" />
+																</div>
+															</FormGroup>
+															<FormGroup>
+																<label className="row-form-label">Tanggal Surat Jawaban Atas Permohonan Keberatan :</label>
+																<div className="row-md-10">
+																	<Field name="tanggal_surat_keberatan">
+																		{({ field, form }) => (
+
+																			<DatePicker
+																				selected={this.state.tglSuratKeberatan || field.value}
+																				onChange={(e) => {
+																					form.setFieldValue(field.name, e);
+																					this.setTglSuratKeberatan(e)
+																				}}
+																				dateFormat="dd/MM/yyyy"
+																				placeholderText="Isi Tanggal"
+																				locale={id}
+																				className="form-control bg-white"
+																			/>
+																		)}
+																	</Field>
+																	<ErrorMessage name="tanggal_surat_keberatan" component="div" className="form-text text-danger" />
+																</div>
+															</FormGroup>
+															<FormGroup>
+																<label className="row-form-label">Dokumen Jawaban Atas Permohonan Keberatan:</label>
 																<div className="row-md-10">
 																	<Field name="dokumen">
 																		{({ field, form }) => (
@@ -293,8 +381,103 @@ class DetailKeberatan extends Component {
 																	<p className="mrgn-top-5">Ukuran setiap dokumen maksimal 15mb</p>
 																</div>
 															</FormGroup>
-															{/* <FormGroup>
-													<div className="row-xl-10"> */}
+
+															<FormGroup>
+																<label className="row-form-label">Tanda Terima Surat Jawaban Permohonan Keberatan :</label>
+																<div className="row-md-10">
+																	<Field name="tanggal_terima_keberatan">
+																		{({ field, form }) => (
+
+																			<DatePicker
+																				selected={this.state.tglTerimaKeberatan || field.value}
+																				onChange={(e) => {
+																					form.setFieldValue(field.name, e);
+																					this.setTglTerimaKeberatan(e)
+																				}}
+																				dateFormat="dd/MM/yyyy"
+																				minDate={tglSuratKeberatan}
+																				placeholderText="Isi Tanggal"
+																				locale={id}
+																				className="form-control bg-white"
+																			/>
+																		)}
+																	</Field>
+																	<ErrorMessage name="tanggal_terima_keberatan" component="div" className="form-text text-danger" />
+																</div>
+															</FormGroup>
+
+															<FormGroup>
+																<label className="row-form-label">Dokumen Tanda Terima Surat Jawaban Permohonan Keberatan:</label>
+																<div className="row-md-10">
+																	<Field name="dokumen_terima_keberatan">
+																		{({ field, form }) => (
+																			<DropzoneWrapper
+																				className=""
+																				onDrop={(e) => {
+																					this.onDropTTSKeberatan(e);
+																					form.setFieldValue(field.name, e);
+																				}}
+																			>
+																				{({ getRootProps, getInputProps, isDragActive }) => {
+																					return (
+																						<div {...getRootProps()} className={"dropzone card" + (isDragActive ? "dropzone-drag-active" : "")}>
+																							<input {...getInputProps()} />
+																							<div className="dropzone-previews flex">
+																								<div className="dropzone-style-1">
+																									<div className="center-ver-hor dropzone-previews flex">{this.state.fileTTSKeberatan.length > 0 ? <Row><span className="text-left">{thumbsTTSKeberatan}</span></Row> :
+																										<div className="text-center fa-2x icon-cloud-upload mr-2 ">
+																											<h5 className="text-center dz-default dz-message">Klik untuk upload dokumen</h5>
+																										</div>
+																									}
+																									</div>
+																								</div>
+																							</div>
+																							<div className="d-flex align-items-center">
+																								<small className="ml-auto">
+																									<button
+																										type="button"
+																										className="btn btn-link"
+																										onClick={(e) => {
+																											this.clearFilesTTSKeberatan(e);
+																											form.setFieldValue(field.name, []);
+																										}}
+																									>
+																										Reset dokumen
+																									</button>
+																								</small>
+																							</div>
+																						</div>
+																					);
+																				}}
+																			</DropzoneWrapper>
+																		)}
+																	</Field>
+																	<ErrorMessage name="dokumen_terima_keberatan" component="div" className="form-text text-danger" />
+																	<p className="mrgn-top-5">Ukuran setiap dokumen maksimal 15mb</p>
+																</div>
+															</FormGroup>
+															<FormGroup>
+																<label className="row-form-label">Akhir Permohonan Banding : </label>
+																<p>Note : 21 hari kerja</p>
+																<div className="row-md-10">
+																	<Field name="tanggal_akhir_banding">
+																		{({ field, form }) => (
+																			<DatePicker
+																				selected={this.state.tglAkhirBanding || field.value}
+																				onChange={(e) => {
+																					form.setFieldValue(field.name, e);
+																				}}
+																				minDate={tglTerimaKeberatan}
+																				dateFormat="dd/MM/yyyy"
+																				placeholderText="Isi Tanggal"
+																				locale={id}
+																				className="form-control bg-white"
+																			/>
+																		)}
+																	</Field>
+																	<ErrorMessage name="tanggal_akhir_banding" component="div" className="form-text text-danger" />
+																</div>
+															</FormGroup>
 															<FormGroup row>
 																<div className="col-xl-10">
 																	<Button color className="color-3e3a8e btn-login" type="submit">
@@ -302,11 +485,7 @@ class DetailKeberatan extends Component {
 																	</Button>
 																</div>
 															</FormGroup>
-															{/* <Button color="primary" onClick={sanksi.data.jawaban?.keberatan ? this.toggleModal : this.handelSimpan}>
-															Simpan
-														</Button> */}
-															{/* </div>
-												</FormGroup> */}
+
 														</Form>
 													)}
 												</Formik>

+ 1 - 0
pages/app/keberatan/index.js

@@ -25,6 +25,7 @@ class Keberatan extends Component {
 
 	render() {
 		const { sanksi } = this.state;
+		console.log(sanksi)
 		return (
 			<ContentWrapper>
 				<div className="content-heading">

+ 38 - 1
pages/app/laporan-delegasi/index.js

@@ -9,6 +9,8 @@ import { connect } from "react-redux";
 import Loader from "@/components/Common/Loader";
 import Router from "next/router";
 import { createLog } from "@/actions/log";
+import swal from "sweetalert2";
+
 
 class Pelaporan extends Component {
 	constructor(props) {
@@ -49,6 +51,41 @@ class Pelaporan extends Component {
 		Router.push(url);
 	};
 
+	excelMenu = () => {
+		const url = getExcel(this.props.token, "Laporan", {
+			tahun: this.state.tahun,
+			pelaporan: true,
+		});
+		if (this.state.graph.data.jumlah_laporan.dikti && this.state.graph.data.jumlah_laporan.ditutup && this.state.graph.data.jumlah_laporan.lldikti) {
+			Router.push(url);
+		} else {
+			swal.fire({
+				title: "Data Kosong",
+				icon: "error",
+				confirmButtonColor: "#3e3a8e",
+			});
+		}
+	};
+	excelSemua = () => {
+		const url = getExcel(this.props.token, "Laporan", {
+			tahun: this.state.tahun,
+			pelaporan: true,
+			penjadwalan: true,
+			pemeriksaan: true,
+			sanksi: true,
+
+		});
+		if (this.state.graph.data.jumlah_laporan.dikti && this.state.graph.data.jumlah_laporan.ditutup && this.state.graph.data.jumlah_laporan.lldikti) {
+			Router.push(url);
+		} else {
+			swal.fire({
+				title: "Data Kosong",
+				icon: "error",
+				confirmButtonColor: "#3e3a8e",
+			});
+		}
+	};
+
 	render() {
 		const { pelaporan, graph } = this.state;
 		return (
@@ -57,7 +94,7 @@ class Pelaporan extends Component {
 					<div className="font-color-white">Laporan Delegasi</div>
 				</div>
 				<Row>
-					<Col lg="4">{graph?.data ? <CaseProgress data={graph.data} nextButton={this.nextButton} prevButton={this.prevButton} tahun={this.state.tahun} excel={this.excel} /> : <Loader />}</Col>
+					<Col lg="4">{graph?.data ? <CaseProgress data={graph.data} nextButton={this.nextButton} prevButton={this.prevButton} tahun={this.state.tahun} excel={this.excel} excelMenu={this.excelMenu} excelSemua={this.excelSemua} /> : <Loader />}</Col>
 					<Col lg="8">{pelaporan?.data ? <TableLaporan listData={pelaporan.data} to="/app/laporan-delegasi/detail" linkName="Detail" /> : <Loader />}</Col>
 				</Row>
 			</ContentWrapper>

+ 19 - 11
pages/app/pelaporan/index.js

@@ -10,6 +10,7 @@ import { connect } from "react-redux";
 import Loader from "@/components/Common/Loader";
 import Router from "next/router";
 import { createLog } from "@/actions/log";
+import swal from "sweetalert2";
 
 class Pelaporan extends Component {
 	constructor(props) {
@@ -63,7 +64,15 @@ class Pelaporan extends Component {
 			tahun: this.state.tahun,
 			pelaporan: true,
 		});
-		Router.push(url);
+		if (this.state.graph.data.jumlah_laporan.dikti && this.state.graph.data.jumlah_laporan.ditutup && this.state.graph.data.jumlah_laporan.lldikti) {
+			Router.push(url);
+		} else {
+			swal.fire({
+				title: "Data Kosong",
+				icon: "error",
+				confirmButtonColor: "#3e3a8e",
+			});
+		}
 	};
 	excelSemua = () => {
 		const url = getExcel(this.props.token, "Laporan", {
@@ -74,17 +83,16 @@ class Pelaporan extends Component {
 			sanksi: true,
 
 		});
-		Router.push(url);
+		if (this.state.graph.data.jumlah_laporan.dikti && this.state.graph.data.jumlah_laporan.ditutup && this.state.graph.data.jumlah_laporan.lldikti) {
+			Router.push(url);
+		} else {
+			swal.fire({
+				title: "Data Kosong",
+				icon: "error",
+				confirmButtonColor: "#3e3a8e",
+			});
+		}
 	};
-
-	// excel = () => {
-	// 	const url = getExcel(this.props.token, "Laporan", {
-	// 		tahun: this.state.tahun,
-	// 		pelaporan: true,
-	// 	});
-	// 	Router.push(url);
-	// };
-
 	render() {
 		const { pelaporan, graph, newLaporan } = this.state;
 

+ 24 - 2
pages/app/pemeriksaan/index.js

@@ -10,6 +10,8 @@ import Loader from "@/components/Common/Loader";
 import Link from "next/link";
 import Button from "reactstrap/lib/Button";
 import Router from "next/router";
+import swal from "sweetalert2";
+
 
 class Pemeriksaan extends Component {
 	constructor(props) {
@@ -43,13 +45,24 @@ class Pemeriksaan extends Component {
 	shouldComponentUpdate = (prevProps, prevState) => {
 		if (prevState.graph !== this.state.graph) return true;
 	};
+
+
 	excelMenu = () => {
 		const url = getExcel(this.props.token, "Laporan", {
 			tahun: this.state.tahun,
 			pemeriksaan: true,
 		});
-		Router.push(url);
+		if (this.state.graph.data.evaluasi.hasEvaluasi) {
+			Router.push(url);
+		} else {
+			swal.fire({
+				title: "Data Kosong",
+				icon: "error",
+				confirmButtonColor: "#3e3a8e",
+			});
+		}
 	};
+
 	excelSemua = () => {
 		const url = getExcel(this.props.token, "Laporan", {
 			tahun: this.state.tahun,
@@ -59,11 +72,20 @@ class Pemeriksaan extends Component {
 			sanksi: true,
 
 		});
-		Router.push(url);
+		if (this.state.graph.data.evaluasi.hasEvaluasi) {
+			Router.push(url);
+		} else {
+			swal.fire({
+				title: "Data Kosong",
+				icon: "error",
+				confirmButtonColor: "#3e3a8e",
+			});
+		}
 	};
 	excel = () => {
 		const url = getExcel(this.props.token, "Laporan", { tahun: this.state.tahun });
 		Router.push(url);
+
 	};
 
 	render() {

+ 20 - 2
pages/app/penjadwalan/index.js

@@ -10,6 +10,8 @@ import Loader from "@/components/Common/Loader";
 import Link from "next/link";
 import Button from "reactstrap/lib/Button";
 import Router from "next/router";
+import swal from "sweetalert2";
+
 
 class Penjadwalan extends Component {
 	constructor(props) {
@@ -48,7 +50,15 @@ class Penjadwalan extends Component {
 			tahun: this.state.tahun,
 			penjadwalan: true,
 		});
-		Router.push(url);
+		if (this.state.graph.data.jadwal.hasJadwal && this.state.graph.data.jadwal.notHasJadwal) {
+			Router.push(url);
+		} else {
+			swal.fire({
+				title: "Data Kosong",
+				icon: "error",
+				confirmButtonColor: "#3e3a8e",
+			});
+		}
 	};
 	excelSemua = () => {
 		const url = getExcel(this.props.token, "Laporan", {
@@ -59,7 +69,15 @@ class Penjadwalan extends Component {
 			sanksi: true,
 
 		});
-		Router.push(url);
+		if (this.state.graph.data.jadwal.hasJadwal && this.state.graph.data.jadwal.notHasJadwal) {
+			Router.push(url);
+		} else {
+			swal.fire({
+				title: "Data Kosong",
+				icon: "error",
+				confirmButtonColor: "#3e3a8e",
+			});
+		}
 	};
 
 	excel = () => {

+ 20 - 2
pages/app/sanksi/index.js

@@ -10,6 +10,8 @@ import Loader from "@/components/Common/Loader";
 import Link from "next/link";
 import Button from "reactstrap/lib/Button";
 import Router from "next/router";
+import swal from "sweetalert2";
+
 
 class Sanksi extends Component {
 	constructor(props) {
@@ -48,7 +50,15 @@ class Sanksi extends Component {
 			tahun: this.state.tahun,
 			sanksi: true,
 		});
-		Router.push(url);
+		if (this.state.graph.data.sanksi.hasSanksi && this.state.graph.data.sanksi.notHasSanksi) {
+			Router.push(url);
+		} else {
+			swal.fire({
+				title: "Data Kosong",
+				icon: "error",
+				confirmButtonColor: "#3e3a8e",
+			});
+		}
 	};
 	excelSemua = () => {
 		const url = getExcel(this.props.token, "Laporan", {
@@ -59,7 +69,15 @@ class Sanksi extends Component {
 			sanksi: true,
 
 		});
-		Router.push(url);
+		if (this.state.graph.data.sanksi.hasSanksi && this.state.graph.data.sanksi.notHasSanksi) {
+			Router.push(url);
+		} else {
+			swal.fire({
+				title: "Data Kosong",
+				icon: "error",
+				confirmButtonColor: "#3e3a8e",
+			});
+		}
 	};
 
 	excel = () => {

+ 69 - 11
pages/app/sanksi/proses.js

@@ -10,12 +10,15 @@ import UploadSurat from "@/components/Sanksi/UploadSurat";
 import Ringkasan from "@/components/Sanksi/Ringkasan";
 import TablePenetapanSanksi from "@/components/Sanksi/TablePenetapanSanksi";
 import Link from "next/link";
-import { getOneLaporan } from "@/actions/pelaporan";
+import { getOneLaporan, updateLaporan } from "@/actions/pelaporan";
 import { createSanksi } from "@/actions/sanksi";
 import { getPelanggaran, getPelanggaranSanksi } from "@/actions/pelanggaran";
 import { connect } from "react-redux";
 import Loader from "@/components/Common/Loader";
 import { ToastContainer, toast } from "react-toastify";
+import BeritaAcara from "@/components/Sanksi/BeritaAcara_A";
+import { autosave } from "@/actions/autosave";
+
 
 const stepNavitemStyle = {
 	backgroundColor: "#fcfcfc",
@@ -30,7 +33,8 @@ class ProsesSanksi extends Component {
 			dataUpload: null,
 			dataPelanggaran: {},
 			pelaporan: {},
-			listSanksi: []
+			listSanksi: [],
+			dataSave: {}
 		};
 	}
 
@@ -57,12 +61,24 @@ class ProsesSanksi extends Component {
 			formdata.append("keterangan", this.state.dataUpload.keterangan);
 			formdata.append("from_date", this.state.dataUpload.awalsanksi);
 			formdata.append("to_date", this.state.dataUpload.akhirsanksi);
+			formdata.append("tanggal_terima_sanksi", this.state.dataUpload.terimaSuratSanksi);
+			formdata.append("tanggal_akhir_keberatan", this.state.dataUpload.tglAkhirKeberatan);
 			formdata.append("pelanggaran_id", this.state.dataPelanggaran.data.map((e) => e._id).join());
-			if (this.state.dataUpload.files.length > 0) {
+			if (this.state.dataUpload.files && this.state.dataUpload.files.length > 0) {
 				this.state.dataUpload.files.forEach((e) => {
 					formdata.append("dokumen", e);
 				});
 			}
+			if (this.state.dataUpload.filesBeritaAcara && this.state.dataUpload.filesBeritaAcara.length > 0) {
+				this.state.dataUpload.filesBeritaAcara.forEach((e) => {
+					formdata.append("berita_acara", e);
+				});
+			}
+			if (this.state.dataUpload.fileTandaTerimaSS && this.state.dataUpload.fileTandaTerimaSS.length > 0) {
+				this.state.dataUpload.fileTandaTerimaSS.forEach((e) => {
+					formdata.append("dokumen_terima_sanksi", e);
+				});
+			}
 			await createSanksi(token, id, formdata);
 			toast.update(toastid, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
 			Router.push({
@@ -73,6 +89,24 @@ class ProsesSanksi extends Component {
 		}
 	};
 
+
+	handleDelegasi = async (data) => {
+		const { token, query } = this.props;
+		const { id } = query;
+		let update = null;
+		const toastid = toast.loading("Please wait...");
+		data.change_role = "true";
+		data.keterangan = "delegasi ke DIKTI"
+		update = await updateLaporan(token, id, data);
+
+		if (!update) {
+			toast.update(toastid, { render: "Laporan gagal didelegasi", type: "error", isLoading: false, autoClose: true, closeButton: true });
+		} else {
+			toast.update(toastid, { render: "Laporan berhasil didelegasi", type: "success", isLoading: false, autoClose: true, closeButton: true });
+			Router.push("/app/sanksi");
+		}
+	};
+
 	toggleStep = (activeStep) => () => {
 		if (this.state.activeStep !== activeStep) {
 			this.setState({
@@ -153,7 +187,7 @@ class ProsesSanksi extends Component {
 												})}
 												onClick={this.toggleStep("4")}
 											>
-												<h4 className="text-left my-3">4. Penetapan Sanksi</h4>
+												<h4 className="text-left my-3">4. Berita Acara Pleno</h4>
 											</NavLink>
 										</NavItem>
 										<NavItem style={stepNavitemStyle}>
@@ -164,7 +198,18 @@ class ProsesSanksi extends Component {
 												})}
 												onClick={this.toggleStep("5")}
 											>
-												<h4 className="text-left my-3">5. Ringkasan</h4>
+												<h4 className="text-left my-3">5. Penetapan Sanksi</h4>
+											</NavLink>
+										</NavItem>
+										<NavItem style={stepNavitemStyle}>
+											<NavLink
+												tag="div"
+												className={classnames({
+													active: this.state.activeStep === "6",
+												})}
+												onClick={this.toggleStep("6")}
+											>
+												<h4 className="text-left my-3">6. Ringkasan</h4>
 											</NavLink>
 										</NavItem>
 									</Nav>
@@ -209,7 +254,7 @@ class ProsesSanksi extends Component {
 										<TabPane tabId="3">
 											<div className="pt-3 mb-3">
 												<h2>Penetapan Jenis Pelanggaran</h2>
-												<TablePenetapanSanksi setCheckedData={this.setCheckedData} />
+												<TablePenetapanSanksi handleDelegasi={this.handleDelegasi} setCheckedData={this.setCheckedData} dataPelanggaran={dataPelanggaran.data} data={pelaporan.data} />
 											</div>
 											<hr />
 											<div className="d-flex">
@@ -222,28 +267,41 @@ class ProsesSanksi extends Component {
 											</div>
 										</TabPane>
 										<TabPane tabId="4">
+											<Card>
+												<BeritaAcara query={this.props.query} dataPelanggaran={dataPelanggaran.data} />
+											</Card>
+											<div className="d-flex">
+												<Button color className="btn-login color-3e3a8e" onClick={this.toggleStep("3")}>
+													<span className="font-color-white">Previous</span>
+												</Button>
+												<Button className="ml-auto btn-login color-3e3a8e" color onClick={this.toggleStep("5")}>
+													<span className="font-color-white">Next</span>
+												</Button>
+											</div>
+										</TabPane>
+										<TabPane tabId="5">
 											<div className="pt-3 mb-3">
 												<h2>Penetapan Sanksi</h2>
-												{this.state.listSanksi && <UploadSurat setUploadSuratSanksi={this.setUploadSuratSanksi} listSanksi={this.state.listSanksi} />}
+												{this.state.listSanksi && <UploadSurat setUploadSuratSanksi={this.setUploadSuratSanksi} listSanksi={this.state.listSanksi} dataPelanggaran={dataPelanggaran.data} query={this.props.query} />}
 											</div>
 											<hr />
 											<div className="d-flex">
-												<Button color className="btn-login color-3e3a8e" onClick={this.toggleStep("3")}>
+												<Button color className="btn-login color-3e3a8e" onClick={this.toggleStep("4")}>
 													<span className="font-color-white">Previous</span>
 												</Button>
-												<Button className="ml-auto btn-login color-3e3a8e" color onClick={this.toggleStep("5")}>
+												<Button className="ml-auto btn-login color-3e3a8e" color onClick={this.toggleStep("6")}>
 													<span className="font-color-white">Next</span>
 												</Button>
 											</div>
 										</TabPane>
-										<TabPane tabId="5">
+										<TabPane tabId="6">
 											<div className="pt-3 mb-3">
 												<h2>Ringkasan</h2>
 												{pelaporan.data ? <Ringkasan dataLaporan={pelaporan.data} dataPelanggaran={dataPelanggaran.data} dataUpload={dataUpload} /> : <Loader />}
 											</div>
 											<hr />
 											<div className="d-flex">
-												<Button color className="btn-login color-3e3a8e" onClick={this.toggleStep("4")}>
+												<Button color className="btn-login color-3e3a8e" onClick={this.toggleStep("5")}>
 													<span className="font-color-white">Previous</span>
 												</Button>
 												<Button className="ml-auto btn-login color-3e3a8e" color onClick={this.done}>

+ 36 - 6
pages/app/tuntas/index.js

@@ -10,6 +10,8 @@ import Loader from "@/components/Common/Loader";
 import Link from "next/link";
 import Button from "reactstrap/lib/Button";
 import Router from "next/router";
+import swal from "sweetalert2";
+
 
 class PelaporanTuntas extends Component {
     constructor(props) {
@@ -37,14 +39,26 @@ class PelaporanTuntas extends Component {
 
     nextButton = async () => {
         const tahun = this.state.tahun + 1;
-        const graph = await getGraph(this.props.token, { evaluasi: true, listJadwal: true, tahun });
-        this.setState({ graph, tahun });
+        const { token } = this.props;
+        let laporanSelesai = await getlaporanselesai(token);
+        laporanSelesai = {
+            ...laporanSelesai, data: {
+                ...laporanSelesai.data, laporan: [...laporanSelesai.data.laporan, ...laporanSelesai.data.sanksi], sanksi: null
+            }
+        }
+        this.setState({ laporanSelesai, tahun });
     };
 
     prevButton = async () => {
         const tahun = this.state.tahun - 1;
-        const graph = await getGraph(this.props.token, { evaluasi: true, listJadwal: true, tahun });
-        this.setState({ graph, tahun });
+        const { token } = this.props;
+        let laporanSelesai = await getlaporanselesai(token);
+        laporanSelesai = {
+            ...laporanSelesai, data: {
+                ...laporanSelesai.data, laporan: [...laporanSelesai.data.laporan, ...laporanSelesai.data.sanksi], sanksi: null
+            }
+        }
+        this.setState({ laporanSelesai, tahun });
     };
 
     shouldComponentUpdate = (prevProps, prevState) => {
@@ -60,7 +74,15 @@ class PelaporanTuntas extends Component {
             tahun: this.state.tahun,
             pelaporan: true,
         });
-        Router.push(url);
+        if (this.state.graph.data.jumlah_ditutup && this.state.graph.data.jumlah_selesai) {
+            Router.push(url);
+        } else {
+            swal.fire({
+                title: "Data Kosong",
+                icon: "error",
+                confirmButtonColor: "#3e3a8e",
+            });
+        }
     };
     excelSemua = () => {
         const url = getExcel(this.props.token, "Laporan", {
@@ -71,7 +93,15 @@ class PelaporanTuntas extends Component {
             sanksi: true,
 
         });
-        Router.push(url);
+        if (this.state.graph.data.jumlah_ditutup && this.state.graph.data.jumlah_selesai) {
+            Router.push(url);
+        } else {
+            swal.fire({
+                title: "Data Kosong",
+                icon: "error",
+                confirmButtonColor: "#3e3a8e",
+            });
+        }
     };
 
     render() {

+ 29 - 6
pages/pt/jawaban-banding/detail.js

@@ -54,12 +54,20 @@ class JawabanBanding extends Component {
 							<Col xl="9">
 								<Card className="card-default">
 									<CardBody>
-										<Row>
-											<Col lg={12}>
-												<DetailSanksi data={sanksi.data} />
-												<DetailJawaban data={sanksi.data.jawaban.banding} sanksiId={sanksi.data._id} />
-											</Col>
-										</Row>
+										{sanksi.data.jawaban?.banding ? (
+											<Row>
+												<Col lg={12}>
+													<DetailSanksi data={sanksi.data} />
+													<DetailJawaban data={sanksi.data.jawaban.banding} sanksiId={sanksi.data._id} />
+												</Col>
+											</Row>)
+											: (
+												<Col lg={12}>
+													<h3 className=" font-weight-bold">Menunggu Jawaban Permohonan Banding</h3>
+													<div className=" tengah"><img className=" tengah" src="/static/img/Wait-Jawaban.png" alt="gambar" /></div>
+												</Col>
+											)}
+
 									</CardBody>
 								</Card>
 							</Col>
@@ -68,6 +76,21 @@ class JawabanBanding extends Component {
 						)}
 						<Col xl="3">{pt && <DetailPT data={pt} />}</Col>
 					</Row>
+					{sanksi.data ? (
+
+						<Col xl="9">
+							<p className="pb-5">
+								<Link href={{ pathname: "/pt/jawaban-keberatan/detail", query: { id: sanksi.data._id } }}>
+									<span className="btn-radius float-left">
+										<Button color="" className="btn-labeled-3-notHover" >
+											<h4 className=" mt-1 mb-md-2 text-center">Previous</h4>
+										</Button>
+									</span>
+								</Link>
+
+							</p>
+						</Col>
+					) : ("")}
 				</div>
 			</ContentWrapper>
 		);

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

@@ -1,6 +1,6 @@
 import React, { Component } from "react";
 import ContentWrapper from "@/components/Layout/ContentWrapper";
-import { getOneSanksi } from "@/actions/sanksi";
+import { getOneSanksi, updatePT } from "@/actions/sanksi";
 import Header from "@/components/Main/Header";
 import DetailPT from "@/components/Main/DetailPT";
 import DetailSanksi from "@/components/Main/DetailSanksi";
@@ -12,6 +12,8 @@ import { Row, Col, Card, CardBody, Button } from "reactstrap";
 import { connect } from "react-redux";
 import { withRouter } from "next/router";
 import Loader from "@/components/Common/Loader";
+import Router from "next/router";
+import { ToastContainer, toast } from "react-toastify";
 
 class JawabanKeberatan extends Component {
 	constructor(props) {
@@ -38,6 +40,9 @@ class JawabanKeberatan extends Component {
 			this.setState({ modal: !this.state.modal });
 		}
 	};
+	toPerbaikan = () => {
+		Router.push("/pt/dokumen-perbaikan");
+	}
 
 	render() {
 		const { sanksi, pt } = this.state;
@@ -66,26 +71,57 @@ class JawabanKeberatan extends Component {
 								<Card className="card-default">
 									<CardBody>
 										<Row>
-											<Col lg={12}>
-												<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.batas_waktu.banding).format("DD MMMM YYYY")}
-															</p>
-															<Button color className="btn-login" onClick={this.toggleModal} disabled={sanksi.data.pengajuan.banding || false}>
-																<span className="font-color-white">
-																	Ajukan Banding
-																</span>
-															</Button>
-														</>
-													) : (
-														<p>Pengajuan ditutup</p>
-													))}
-											</Col>
+											{sanksi.data.jawaban?.keberatan ? (
+												<Col lg={12}>
+													<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 style={{ fontSize: '1vw' }}>
+																	<strong>
+																		Setelah membaca surat keputusan sanksi tersebut, Apakah Perguruan Tinggi bermaksud mengajukan permohonan banding?
+																	</strong>
+																</p>
+																<p style={{ fontSize: '0.8vw' }}>
+																	Pengajuan dilakukan paling lambat tanggal {moment(sanksi.data.batas_waktu.banding).locale("id").format("DD MMMM YYYY")}
+																</p>
+																<p className="lead">
+																	<span className="btn-radius">
+																		<Button color="" disabled={sanksi.data.pengajuan.banding || false} className="btn-labeled-notHover" onClick={this.toggleModal}>
+																			<h4 className="mt-2 mb-md-2 text-center font-color-white pl-3 pr-3">Ya</h4>
+																		</Button>
+																	</span>
+																	<span className="btn-radius">
+																		<Button disabled={sanksi.data.pengajuan.banding || false} color className="btn-labeled-3-notHover" onClick={async () => {
+
+																			const toastid = toast.loading("Please wait...");
+																			try {
+																				const { token, query } = this.props;
+																				await updatePT(token, query.id, { is_pengajuan_keberatan: false })
+																				toast.update(toastid, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
+																				Router.push("/pt/dokumen-perbaikan");
+																			} catch (error) {
+																				toast.update(toastid, { render: "All is not good", type: "error", isLoading: false, autoClose: true, closeButton: true });
+																			}
+																		}
+																		}>
+																			<h4 className=" mt-1 mb-md-2 text-center">Tidak</h4>
+																		</Button>
+																	</span>
+																</p>
+															</>
+														) : (
+															<p>Pengajuan ditutup</p>
+														))}
+
+
+												</Col>) : (
+												<Col lg={12}>
+													<h3 className=" font-weight-bold">Menunggu Jawaban Permohonan Keberatan</h3>
+													<div className=" tengah"><img className=" tengah" src="/static/img/Wait-Jawaban.png" alt="gambar" /></div>
+												</Col>
+											)}
 										</Row>
 									</CardBody>
 								</Card>
@@ -95,9 +131,39 @@ class JawabanKeberatan extends Component {
 						)}
 						<Col xl="3">{pt && <DetailPT data={pt} />}</Col>
 					</Row>
+					{sanksi.data ? (
+
+						<Col xl="9">
+							<p className="pb-5">
+								<Link href={{ pathname: "/pt/keberatan/detail", query: { id: sanksi.data._id } }}>
+									<span className="btn-radius float-left">
+										<Button color="" className="btn-labeled-3-notHover" >
+											<h4 className=" mt-1 mb-md-2 text-center">Previous</h4>
+										</Button>
+									</span>
+								</Link>
+								{sanksi.data.pengajuan?.banding ? (
+									<Link href={{ pathname: "/pt/jawaban-banding/detail", query: { id: sanksi.data._id } }}>
+										<span className="btn-radius float-rigt">
+											<Button color="" className="btn-labeled-notHover" >
+												<h4 className="mt-2 mb-md-2 text-center font-color-white pl-3 pr-3">Next</h4>
+											</Button>
+										</span>
+									</Link>
+								) : (
+									<span className="btn-radius float-rigt">
+										<Button color="" className="btn-labeled-notHover" disabled={true} >
+											<h4 className="mt-2 mb-md-2 text-center font-color-white pl-3 pr-3">Next</h4>
+										</Button>
+									</span>
+								)}
+
+							</p>
+						</Col>
+					) : ("")}
 					{sanksi.data && (
 						<Row>
-							<Col>{sanksi.data.jawaban.keberatan.status !== "Membatalkan Keputusan" && <Riwayat data={sanksi.data.pengajuan?.banding ? sanksi.data.pengajuan.banding : null} />}</Col>
+							<Col>{sanksi.data.jawaban?.keberatan?.status !== "Membatalkan Keputusan" && <Riwayat data={sanksi.data.pengajuan?.banding ? sanksi.data.pengajuan.banding : null} />}</Col>
 						</Row>
 					)}
 				</div>

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

@@ -30,7 +30,7 @@ class JawabanKeberatan extends Component {
 					</span>
 				</div>
 				<Row>
-					<Col lg={12}>{sanksi.data?.length ? <TableSanksi listData={sanksi.data} to="/pt/jawaban-keberatan/detail" linkName="Detail" /> : sanksi.data ? "" : <Loader />} </Col>
+					<Col lg={12}>{sanksi.data?.length ? <TableSanksi listData={sanksi.data} to="/pt/jawaban-keberatan/detail" linkName="Detail" /> : sanksi.data ? "Tidak Ada Sanksi" : <Loader />} </Col>
 				</Row>
 			</ContentWrapper>
 		);

+ 2 - 0
pages/pt/jawaban-pencabutan-sanksi/detail.js

@@ -30,6 +30,8 @@ class DetailJawabanPencabutanSanksi extends Component {
 	render() {
 		const { sanksi, pt } = this.state;
 		const jawaban = sanksi.data?.jawaban.cabut_sanksi || null;
+		// console.log(sanksi)
+		console.log(jawaban)
 		return (
 			<ContentWrapper unwrap>
 				{pt && <Header data={pt} />}

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

@@ -28,7 +28,7 @@ class JawabanCabutSanksi extends Component {
 					<span className="font-color-white">Jawaban Permohonan Pencabutan Sanksi</span>
 				</div>
 				<Row>
-					<Col lg={12}>{sanksi.data?.length ? <TableSanksi listData={sanksi.data} to="/pt/jawaban-pencabutan-sanksi/detail" linkName="Detail" /> : sanksi.data ? "" : <Loader />}</Col>
+					<Col lg={12}>{sanksi.data?.length ? <TableSanksi listData={sanksi.data} to="/pt/jawaban-pencabutan-sanksi/detail" linkName="Detail" /> : sanksi.data ? "Tidak Ada Sanksi" : <Loader />}</Col>
 				</Row>
 			</ContentWrapper>
 		);

+ 67 - 7
pages/pt/keberatan/detail.js

@@ -1,6 +1,6 @@
 import React, { Component } from "react";
 import ContentWrapper from "@/components/Layout/ContentWrapper";
-import { getOneSanksi } from "@/actions/sanksi";
+import { getOneSanksi, updatePT } from "@/actions/sanksi";
 import Header from "@/components/Main/Header";
 import DetailPT from "@/components/Main/DetailPT";
 import DetailSanksi from "@/components/Main/DetailSanksi";
@@ -8,16 +8,19 @@ import Riwayat from "@/components/PT/Keberatan/Riwayat";
 import ModalPermohonan from "@/components/PT/Keberatan/ModalPermohonan";
 import Link from "next/link";
 import moment from "moment";
-import { Row, Col, Card, CardBody, Button } from "reactstrap";
+import { Row, Col, Card, CardBody, Button, Modal, ModalBody, ModalFooter } from "reactstrap";
 import { connect } from "react-redux";
 import { withRouter } from "next/router";
 import Loader from "@/components/Common/Loader";
+import { ToastContainer, toast } from "react-toastify";
+import Router from "next/router";
 
 class Keberatan extends Component {
 	state = {
 		modal: false,
 		sanksi: {},
 		pt: null,
+		modalTidak: false,
 	};
 
 	static getInitialProps = ({ query }) => ({ query });
@@ -36,11 +39,41 @@ class Keberatan extends Component {
 		}
 	};
 
+	setModalTidak = (modalTidak) => {
+		this.setState({
+			modalTidak: !this.state.modalTidak
+		})
+	}
+
 	render() {
 		const { sanksi, pt } = this.state;
 		return (
 			<ContentWrapper unwrap>
-				{sanksi.data && <ModalPermohonan toggleModal={this.toggleModal} modal={this.state.modal} query={this.props.query} data={sanksi.data} />}
+
+				<Modal isOpen={this.state.modalTidak} >
+					<ModalBody>Apakah anda ingin membatalkan permohonan keberatan atas pengenaan sanksi?</ModalBody>
+					<ModalFooter>
+
+						<Button color className="btn-login" onClick={async () => {
+							const toastid = toast.loading("Please wait...");
+							try {
+								const { token, query } = this.props;
+								await updatePT(token, query.id, { is_pengajuan_keberatan: false })
+								toast.update(toastid, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
+								Router.push("/pt/dokumen-perbaikan");
+							} catch (error) {
+								toast.update(toastid, { render: "All is not good", type: "error", isLoading: false, autoClose: true, closeButton: true });
+							}
+						}
+						}>
+							<span className="font-color-white">Ya</span>
+						</Button>
+						<Button color className="btn-v2" onClick={this.setModalTidak}>
+							Tidak
+						</Button>
+					</ModalFooter>
+				</Modal>
+				{sanksi.data && <ModalPermohonan toggleModal={this.toggleModal} modal={this.state.modal} query={this.props.query} data={sanksi.data} sanksi={sanksi} />}
 				{pt && <Header data={pt} />}
 				<div className="p-3">
 					<div className="content-heading">
@@ -71,11 +104,20 @@ class Keberatan extends Component {
 															Setelah membaca surat keputusan sanksi tersebut, jika Perguruan Tinggi bermaksud mengajukan permohonan keberatan maka dapat menekan tombol di bawah ini paling lambat{" "}
 															{moment(sanksi.data.batas_waktu.keberatan).format("DD MMMM YYYY")}
 														</p>
-														<Button color className="color-3e3a8e" onClick={this.toggleModal} disabled={sanksi.data.pengajuan?.keberatan || false}>
-															<span className="font-color-white">
-																Ajukan Permohonan Keberatan
+														<p className=" lead">
+															<span className="btn-radius">
+																<Button color className="btn-labeled-notHover" onClick={this.toggleModal} disabled={sanksi.data.pengajuan?.keberatan || false}>
+																	<h4 className="mt-2 mb-md-2 text-center font-color-white pl-3 pr-3 font-weight-normal ">
+																		Ajukan Permohonan Keberatan
+																	</h4>
+																</Button>
+															</span>
+															<span className="btn-radius">
+																<Button disabled={sanksi.data.pengajuan?.keberatan || false} color className="btn-labeled-3-notHover" onClick={this.setModalTidak} >
+																	<h4 className=" mt-1 mb-md-2 text-center">Batalkan Pengajuan Permohonan Keberatan</h4>
+																</Button>
 															</span>
-														</Button>
+														</p>
 													</>
 												) : (
 													<p>Pengajuan ditutup</p>
@@ -90,6 +132,24 @@ class Keberatan extends Component {
 						)}
 						<Col xl="3">{pt && <DetailPT data={pt} />}</Col>
 					</Row>
+					{sanksi.data && (
+						<Row>
+							{sanksi.data.pengajuan?.keberatan ? (
+								<Col xl="9">
+									<p className=" lead float-right">
+										<Link href={{ pathname: "/pt/jawaban-keberatan/detail", query: { id: sanksi.data._id } }}>
+											<span className="btn-radius">
+												<Button color="" className="btn-labeled-notHover" >
+													<h4 className="mt-2 mb-md-2 text-center font-color-white pl-3 pr-3">Next</h4>
+												</Button>
+											</span>
+										</Link>
+
+									</p>
+								</Col>
+							) : ("")}
+
+						</Row>)}
 					{sanksi.data && (
 						<Row>
 							<Col>

+ 1 - 1
pages/pt/keberatan/index.js

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

+ 152 - 0
pages/pt/sanksi/detail.js

@@ -0,0 +1,152 @@
+import React, { Component } from "react";
+import ContentWrapper from "@/components/Layout/ContentWrapper";
+import { getOneSanksi, updatePT } 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/Keberatan/Riwayat";
+import ModalPermohonan from "@/components/PT/Keberatan/ModalPermohonan";
+import Link from "next/link";
+import moment from "moment";
+import { Row, Col, Card, CardBody, Button, Modal, ModalBody, ModalFooter } from "reactstrap";
+import { connect } from "react-redux";
+import Router from "next/router";
+import Loader from "@/components/Common/Loader";
+import { ToastContainer, toast } from "react-toastify";
+
+class Sanksi extends Component {
+	state = {
+		modal: false,
+		sanksi: {},
+		pt: null,
+	};
+
+	static getInitialProps = ({ query }) => ({ query });
+
+	componentDidMount = async () => {
+		const { token, query } = this.props;
+		const sanksi = await getOneSanksi(token, query.id);
+		updatePT(token, query.id, { is_read: true })
+		this.setState({ sanksi, pt: sanksi.data.laporan.pt });
+	};
+	setModal = (modal) => {
+		this.setState({
+			modal: !this.state.modal
+		})
+	}
+
+	render() {
+		const { sanksi, pt } = this.state;
+		console.log(sanksi)
+		return (
+			<ContentWrapper unwrap>
+				<Modal isOpen={this.state.modal} toggle={this.props.toggleModal}>
+					<ModalBody>Apakah anda akan tidak mengajukan permohonan keberatan atas pengenaan sanksi?</ModalBody>
+					<ModalFooter>
+						<Button color className="btn-login" onClick={async () => {
+							const toastid = toast.loading("Please wait...");
+							try {
+								const { token, query } = this.props;
+								await updatePT(token, query.id, { is_pengajuan_keberatan: false })
+								toast.update(toastid, { render: "All is good", type: "success", isLoading: false, autoClose: true, closeButton: true });
+								Router.push("/pt/dokumen-perbaikan");
+							} catch (error) {
+								toast.update(toastid, { render: "All is not good", type: "error", isLoading: false, autoClose: true, closeButton: true });
+							}
+						}
+						}>
+							<span className="font-color-white">Ya</span>
+						</Button>
+						<Button color className="btn-v2" onClick={this.setModal}>
+							Tidak
+						</Button>
+					</ModalFooter>
+				</Modal>
+				{pt && <Header data={pt} />}
+				<div className="p-3">
+					<div className="content-heading">
+						<span className="font-color-white">
+							Sanksi
+						</span>
+						<div className="ml-auto">
+							<Link href="/pt/keberatan">
+								<Button className="color-3e3a8e" color>
+									<span className="font-color-white">
+										&lt; Kembali
+									</span>
+								</Button>
+							</Link>
+						</div>
+					</div>
+					<Row>
+						{sanksi.data ? (
+							<Col xl="9">
+								<Card className="card-default">
+									<CardBody>
+										<Row>
+											<Col lg={12}>
+												<DetailSanksi data={sanksi.data} />
+												{new Date(sanksi.data.batas_waktu.keberatan).getTime() > Date.now() ? (
+													<>
+														<p style={{ fontSize: '1vw' }}>
+															<strong>
+																Setelah membaca surat keputusan sanksi tersebut, Apakah Perguruan Tinggi bermaksud mengajukan keberatan?
+															</strong>
+														</p>
+														<p style={{ fontSize: '0.8vw' }}>
+															Pengajuan dilakukan paling lambat tanggal {moment(sanksi.data.batas_waktu.keberatan).locale("id").format("DD MMMM YYYY")}
+														</p>
+														<p className="lead">
+															<Link href={{ pathname: "/pt/keberatan/detail", query: { id: sanksi.data._id } }}>
+																<span className="btn-radius">
+																	<Button color="" className="btn-labeled-notHover" onClick={async () => {
+																		// const toastid = toast.loading("Please wait...");
+																		try {
+																			const { token, query } = this.props;
+																			await updatePT(token, query.id, { is_pengajuan_keberatan: true })
+																			// toast.update(toastid, { render: "Berhasil", type: "success", isLoading: false, autoClose: true, closeButton: true });
+																		} catch (error) {
+																			// toast.update(toastid, { render: "Gagal", type: "error", isLoading: false, autoClose: true, closeButton: true });
+																		}
+																	}
+
+																	}>
+																		<h4 className="mt-2 mb-md-2 text-center font-color-white pl-3 pr-3">Ya</h4>
+																	</Button>
+																</span>
+															</Link>
+															<span className="btn-radius">
+																<Button disabled={sanksi.data.is_pengajuan_keberatan === true || sanksi.data.is_pengajuan_keberatan === false} color className="btn-labeled-3-notHover" onClick={this.setModal} >
+																	<h4 className=" mt-1 mb-md-2 text-center">Tidak</h4>
+																</Button>
+															</span>
+														</p>
+													</>
+												) : (
+													<p>Pengajuan ditutup</p>
+												)}
+											</Col>
+										</Row>
+									</CardBody>
+								</Card>
+							</Col>
+						) : (
+							<Loader />
+						)}
+						<Col xl="3">{pt && <DetailPT data={pt} />}</Col>
+					</Row>
+					{/* {sanksi.data && (
+						<Row>
+							<Col>
+								<Riwayat data={sanksi.data?.pengajuan?.keberatan ? sanksi.data.pengajuan.keberatan : null} />
+							</Col>
+						</Row>
+					)} */}
+				</div>
+			</ContentWrapper >
+		);
+	}
+}
+
+const mapStateToProps = (state) => ({ user: state.user, token: state.token });
+export default connect(mapStateToProps)(Sanksi);

+ 39 - 0
pages/pt/sanksi/index.js

@@ -0,0 +1,39 @@
+import React, { Component } from "react";
+import ContentWrapper from "@/components/Layout/ContentWrapper";
+import { Row, Col } from "reactstrap";
+import { getSanksi } from "@/actions/sanksi";
+import TableSanksi from "@/components/PT/Sanksi/TableSanksi";
+import { connect } from "react-redux";
+import Loader from "@/components/Common/Loader";
+class Sanksi extends Component {
+	constructor(props) {
+		super(props);
+		this.state = {
+			sanksi: {},
+		};
+	}
+
+	componentDidMount = async () => {
+		const { token } = this.props;
+		const sanksi = await getSanksi(token);
+		this.setState({ sanksi });
+	};
+
+	render() {
+		const { sanksi } = this.state;
+		return (
+			<ContentWrapper>
+				<div className="content-heading">
+					<span className="font-color-white">
+						Sanksi
+					</span></div>
+				<Row>
+					<Col lg={12}>{sanksi.data?.length ? <TableSanksi listData={sanksi.data} to="/pt/sanksi/detail" toKeberatan="/pt/keberatan/detail" toPerbaikan="/pt/dokumen-perbaikan/detail" toJwbKeberatan="/pt/jawaban-keberatan/detail" toJwbBanding="/pt/jawaban-banding/detail" toJwbBanding2="/pt/jawaban-banding/detail" toCabutSanksi="/pt/pencabutan-sanksi/detail" toJwbCabutSanksi="/pt/jawaban-pencabutan-sanksi/detail" linkName="Detail" /> : sanksi.data ? "Tidak ada Sanksi" : <Loader />}</Col>
+				</Row>
+			</ContentWrapper>
+		);
+	}
+}
+
+const mapStateToProps = (state) => ({ user: state.user, token: state.token });
+export default connect(mapStateToProps)(Sanksi);

BIN
public/static/img/Wait-Jawaban.png


+ 46 - 0
styles/bootstrap/_buttons.scss

@@ -224,6 +224,8 @@ input[type="button"] {
   }
 }
 
+
+
 .btn-labeled-3 {
   border: #3e3a8e solid 2px;
   padding-top: 0;
@@ -239,6 +241,50 @@ input[type="button"] {
     color: #3e3a8e;
   }
 }
+.btn-labeled-4 {
+  border: #3e3a8e solid 2px;
+  padding-top: 0;
+  padding-bottom: 0;
+  margin-top: 3%;
+  color: #3e3a8e;
+  background: white;
+  transition: ease background-color 250ms;
+
+  &:hover {
+    background-color: #e9e8e8;
+    opacity: 0.9;
+    color: #3e3a8e;
+  }
+}
+.btn-labeled-3-notHover {
+  border: #3e3a8e solid 2px;
+  padding-top: 0;
+  padding-bottom: 0;
+  margin-top: 3%;
+  color: #3e3a8e;
+  background: transparent;
+  transition: ease background-color 250ms;
+}
+
+.btn-radius .btn-labeled-3-notHover {
+  border-radius: 7px;
+}
+
+.btn-labeled-notHover {
+  padding-top: 0;
+  padding-bottom: 0;
+  margin-right: 20px;
+  margin-top: 3%;
+  background: $colorbutton;
+  display: inline;
+  border-radius: 7px;
+  transition: ease background-color 250ms;
+
+}
+
+.btn-radius .btn-labeled-notHover {
+  border-radius: 7px;
+}
 
 .btn-radius .btn-labeled-3 {
   border-radius: 7px;

+ 140 - 2
styles/bootstrap/_progress.scss

@@ -1,8 +1,13 @@
 // Disable animation if transitions are disabled
 @if $enable-transitions {
   @keyframes progress-bar-stripes {
-    from { background-position: $progress-height 0; }
-    to { background-position: 0 0; }
+    from {
+      background-position: $progress-height 0;
+    }
+
+    to {
+      background-position: 0 0;
+    }
   }
 }
 
@@ -45,3 +50,136 @@
     }
   }
 }
+
+
+.BA-logo {
+  width: 250px;
+  margin-left: auto;
+  margin-right: auto;
+  padding-bottom: 10px;
+}
+
+.BA-header {
+  font-family: "Times New Roman", Times, serif;
+  text-align: center;
+  padding-bottom: 20px;
+}
+
+.BA-div {
+  padding-top: 100px;
+}
+
+.BA-p p {
+  padding: 10px;
+}
+
+.BA-body {
+  font-family: "Times New Roman", Times, serif;
+  padding-top: 0px;
+  padding-left: 50px;
+  padding-right: 50px;
+
+}
+
+.demo {
+  border: 1px solid #C0C0C0;
+  border-collapse: collapse;
+  padding: 5px;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+.demo th {
+  border: 1px solid #C0C0C0;
+  padding: 5px;
+  background: #F0F0F0;
+  text-align: center;
+}
+
+.demo td {
+  border: 1px solid #C0C0C0;
+  padding: 5px;
+  height: 100px;
+  min-width: 200px;
+}
+
+.table-a {
+  border: 1px solid #C0C0C0;
+  border-collapse: collapse;
+  margin-top: 20px;
+  margin-bottom: 20px;
+  padding: 5px;
+  margin-left: -128px auto;
+  margin-right: auto;
+  table-layout: fixed;
+}
+
+.table-a th {
+  border: 1px solid #C0C0C0;
+  padding: 5px;
+  background: #F0F0F0;
+  text-align: center;
+}
+
+.table-a td {
+  border: 1px solid #C0C0C0;
+  padding: 5px;
+  word-wrap: break-word;
+  max-width: 150px;
+}
+
+#footer {
+  position: fixed;
+  width: 100%;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  text-align: center;
+  color: #979595;
+}
+
+////////////////////////////-----SuratBA_A
+
+// body {
+//   margin: 0;
+//   padding: 0;
+//   background-color: #FAFAFA;
+//   font: 12pt "Tahoma";
+// }
+
+// * {
+//   box-sizing: border-box;
+//   -moz-box-sizing: border-box;
+// }
+
+// .page {
+//   width: 21cm;
+//   min-height: 29.7cm;
+//   padding: 2cm;
+//   margin: 1cm auto;
+//   border: 1px #D3D3D3 solid;
+//   border-radius: 5px;
+//   background: white;
+//   box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
+// }
+
+// .subpage {
+//   padding: 1cm;
+//   border: 5px red solid;
+//   height: 256mm;
+//   outline: 2cm #FFEAEA solid;
+// }
+
+// @page {
+//   size: A4;
+//   margin: 0;
+// }
+
+// @media print {
+
+//   body,
+//   page[size="A4"] {
+//     margin: 0;
+//     box-shadow: 0;
+//   }
+// }