MIF_E31231060/resources/views/riwayat-prediksi.blade.php

1739 lines
53 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<link rel="icon" type="image/png" href="{{ asset('images/logo-pmi.png') }}">
<title>RIWAYAT PREDIKSI - UDD PMI KABUPATEN JEMBER</title>
<style>
:root {
--primary: #d32f2f;
--primary-dark: #9a0007;
--primary-soft: #fff1f1;
--bg: #f7faff;
--border: #e5e7eb;
--text: #1f2937;
}
body {
font-family: Poppins, sans-serif;
background: var(--bg);
padding: 28px;
color: var(--text);
overflow-x: hidden;
overflow-y: auto;
margin: 0;
}
.card {
position: relative;
width: 100%;
display: flex;
flex-direction: column;
background: white;
backdrop-filter: blur(14px);
border-radius: 8px;
border: 1px solid rgba(255, 95, 95, 0.6);
box-shadow: 0 10px 30px rgba(15, 23, 42, 0.08);
overflow: hidden;
}
.header {
justify-content: space-between;
position: relative;
display: flex;
align-items: center;
gap: 14px;
background:
linear-gradient(135deg,
#d32f2f 0%,
#b71c1c 45%,
#7f0000 100%);
font-size: 18px;
font-weight: 700;
letter-spacing: .4px;
color: white;
padding: 20px 30px;
overflow: hidden;
border-bottom:
1px solid rgba(255, 255, 255, 0.08);
}
.header-left {
display: flex;
align-items: center;
gap: 14px;
}
.header-nav {
display: flex;
gap: 10px;
width: 600px;
}
.header-btn {
flex: 1;
display: flex;
align-items: center;
gap: 10px;
padding: 10px 14px;
border-radius: 5px;
text-decoration: none;
font-size: 13px;
font-weight: 600;
transition: .25s ease;
border: 1px solid rgba(255, 255, 255, .15);
color: white;
}
.header-btn:nth-child(1) {
background: linear-gradient(135deg,
#5b8def,
#3c6fd7);
}
.header-btn:nth-child(1):hover {
background: linear-gradient(135deg,
#6e9fff,
#4b84f7);
}
.header-btn:nth-child(1) i {
color: #eaf2ff;
}
.header-btn:nth-child(2) {
background: linear-gradient(135deg,
#d98a3d,
#c97828);
}
/* .header-btn:nth-child(2):hover {
background: linear-gradient(135deg,
#e69c5a,
#d98a3d);
} */
.header-btn:nth-child(2) i {
color: #fff4e8;
}
.header-btn:nth-child(3) {
background: linear-gradient(135deg,
#22c55e,
#15803d);
}
.header-btn:nth-child(3):hover {
background: linear-gradient(135deg,
#34d399,
#16a34a);
}
.header-btn:nth-child(3) i {
color: #fff1f1;
}
.header-btn:hover {
transform: translateY(-2px);
filter: brightness(1.05);
color: white;
}
.header-btn.active {
pointer-events: none;
cursor: default;
}
.refresh-btn {
min-width: 45px;
align-self: stretch;
border: none;
border-radius: 5px;
background:
linear-gradient(135deg,
#ef4444,
#b91c1c);
color: white;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: .25s;
}
.refresh-icon {
font-size: 20px;
transition: transform .3s ease;
}
.refresh-btn:hover .refresh-icon {
transform: rotate(180deg);
}
.header-left i,
.header-btn i {
position: relative;
font-size: 18px;
width: 40px;
height: 40px;
border-radius: 5px;
display: flex;
align-items: center;
justify-content: center;
color: rgba(255, 255, 255, .96);
background: linear-gradient(145deg,
rgba(255, 255, 255, .22),
rgba(255, 255, 255, .08));
border: 1px solid rgba(255, 255, 255, .18);
backdrop-filter: blur(10px);
box-shadow:
inset 0 1px 1px rgba(255, 255, 255, .24),
inset 0 -1px 1px rgba(255, 255, 255, .05),
0 10px 18px rgba(0, 0, 0, .16),
0 4px 8px rgba(0, 0, 0, .10);
}
.toolbar {
padding: 20px 24px;
display: flex;
justify-content: space-between;
gap: 18px;
border-bottom: 1px solid rgba(215, 215, 215, 0.7);
background:
linear-gradient(180deg,
rgba(255, 255, 255, .88),
rgba(255, 255, 255, .72));
backdrop-filter: blur(10px);
}
input,
select {
height: 40px;
border: 1px solid var(--border);
border-radius: 8px;
padding: 0 12px;
font-size: 13px;
transition: .2s;
background: #fff;
}
input:focus,
select:focus {
border-color: var(--primary);
box-shadow: 0 0 0 2px rgba(211, 47, 47, .1);
}
.right-tools {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 10px;
}
.right-tools input {
width: 270px;
height: 44px;
padding: 0 14px 0 40px;
border: 1px solid #efd0d0;
border-radius: 10px;
background:
linear-gradient(180deg,
#ffffff,
#fff8f8);
box-shadow:
inset 0 2px 4px rgba(0, 0, 0, .03),
0 4px 10px rgba(15, 23, 42, .04);
transition: .25s ease;
font-size: 13px;
font-weight: 500;
}
.left-tools {
display: flex;
align-items: center;
gap: 10px;
}
.left-tools span {
font-size: 13px;
color: #454545;
}
.left-tools select {
width: 40px;
height: 34px;
padding: 0 6px;
font-size: 13px;
border-radius: 6px;
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.15);
appearance: none;
text-align: center;
}
.left-tools select:hover {
border-color: #d1d5db;
}
.left-tools select:focus {
border-color: var(--primary);
box-shadow:
inset 0 2px 5px rgba(0, 0, 0, 0.08),
0 0 0 2px rgba(211, 47, 47, 0.15);
}
.search-icon {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
width: 18px;
height: 18px;
display: flex;
align-items: center;
justify-content: center;
color: #d32f2f;
font-size: 13px;
opacity: .9;
pointer-events: none;
z-index: 2;
transition: all .25s ease;
}
.search-box {
position: relative;
display: flex;
align-items: center;
}
.search-box:hover .search-icon {
color: #9a0007;
transform: translateY(-50%) scale(1.08);
}
.search-box input:focus+.search-icon,
.search-box:focus-within .search-icon {
color: #9a0007;
}
.search-box input:focus {
background: #fff;
border-color: var(--primary);
box-shadow: 0 4px 12px rgba(211, 47, 47, .15);
}
.search-box input:focus {
background: #fff;
border-color: #ef4444;
box-shadow:
0 0 0 4px rgba(239, 68, 68, .08),
0 10px 20px rgba(239, 68, 68, .10);
}
.print-btn {
width: 44px;
height: 44px;
border: none;
border-radius: 8px;
background:
linear-gradient(135deg,
#ffa94d 0%,
#f97316 45%,
#ea580c 100%);
color: white;
cursor: pointer;
font-size: 15px;
box-shadow:
0 4px 10px rgba(235, 143, 37, 0.22),
inset 0 1px 1px rgba(255, 255, 255, .14);
transition: all .22s ease;
}
.print-btn:hover {
transform: translateY(-2px);
box-shadow:
0 8px 16px rgba(235, 169, 37, 0.18);
}
.print-btn.disabled,
.print-btn:disabled {
opacity: .45;
cursor: not-allowed;
pointer-events: none;
transform: none !important;
box-shadow:
0 2px 6px rgba(0, 0, 0, .08);
}
.filter-toggle {
width: 44px;
height: 44px;
border: none;
border-radius: 8px;
background:
linear-gradient(135deg,
#ef4444,
#991b1b);
color: white;
cursor: pointer;
font-size: 15px;
box-shadow:
0 10px 20px rgba(239, 68, 68, .22),
inset 0 1px 1px rgba(255, 255, 255, .18);
transition: all .22s ease;
}
.filter-toggle:hover {
transform: translateY(-2px);
box-shadow:
0 16px 26px rgba(239, 68, 68, .28);
}
.month-filter {
width: 180px;
height: 44px;
border-radius: 10px;
border: 1px solid #efd4d4;
padding: 0 14px 0 40px;
font-size: 13px;
font-family: Poppins, sans-serif;
font-weight: 500;
background:
linear-gradient(180deg,
#fff,
#fff7f7);
box-shadow:
inset 0 2px 4px rgba(0, 0, 0, .03),
0 4px 10px rgba(15, 23, 42, .04);
transition: .25s ease;
cursor: pointer;
}
.month-filter:hover {
border-color: #ef9a9a;
transform: translateY(-1px);
box-shadow:
0 10px 18px rgba(211, 47, 47, .12);
}
.month-filter:focus {
outline: none;
border-color: #ef4444;
background: #fff;
box-shadow:
0 0 0 4px rgba(239, 68, 68, .08),
0 10px 20px rgba(239, 68, 68, .10);
}
.month-filter::-webkit-calendar-picker-indicator {
opacity: 0;
cursor: pointer;
position: absolute;
right: 0;
width: 100%;
height: 100%;
}
.month-icon {
position: absolute;
left: 14px;
top: 50%;
transform: translateY(-50%);
font-size: 15px;
color: #d32f2f;
pointer-events: none;
z-index: 2;
}
.filter-stack {
display: flex;
flex-direction: column;
gap: 10px;
align-items: flex-end;
}
.filter-row {
display: flex;
align-items: center;
gap: 12px;
background: rgba(255, 255, 255, 0.95);
border: 1px solid rgba(239, 68, 68, 0.19);
padding: 12px;
border-radius: 7px;
box-shadow:
0 8px 22px rgba(15, 23, 42, 0.05);
}
.jenis-panel {
width: 100%;
display: flex;
flex-wrap: wrap;
gap: 10px;
overflow: hidden;
max-height: 0;
opacity: 0;
transition: all .35s ease;
padding: 0;
}
.jenis-panel.show {
max-height: 200px;
opacity: 1;
padding: 4px 0 0 0;
}
.jenis-chip {
border: 1px solid #f2b3b3;
background: white;
padding: 8px 14px;
border-radius: 8px;
font-size: 12px;
cursor: pointer;
transition: all .22s ease;
color: #555;
font-weight: 600;
box-shadow:
0 2px 6px rgba(15, 23, 42, .03);
}
.jenis-chip:hover {
background: #fff0f0;
color: #d32f2f;
border-color: #ef9a9a;
transform: translateY(-1px);
}
.jenis-chip.active {
background:
linear-gradient(135deg,
#ef4444,
#991b1b);
color: white;
border-color: transparent;
box-shadow:
0 10px 18px rgba(239, 68, 68, .22);
}
.delete-btn {
width: 36px;
height: 36px;
border-radius: 8px;
border: none;
background:
linear-gradient(135deg,
#ef4444,
#b91c1c);
color: #fff;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all .22s ease;
font-size: 13px;
box-shadow:
0 8px 18px rgba(239, 68, 68, .22);
}
.delete-btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 14px rgba(211, 47, 47, 0.35);
}
.delete-btn:active {
transform: scale(0.9);
}
.sort-icons {
display: inline-flex;
flex-direction: column;
margin-left: 6px;
vertical-align: middle;
}
.sort-icons i {
font-size: 9px;
line-height: 9px;
color: #9a0007;
transition: all .2s ease;
}
th:hover .sort-icons i {
color: #9a0007;
}
.sort-icons i:hover {
transform: scale(1.2);
color: #d32f2f;
}
.sort-icons .active {
color: #d32f2f;
transform: scale(1.15);
}
.table-wrap {
width: 100%;
overflow-x: auto;
overflow-y: visible;
-webkit-overflow-scrolling: touch;
}
table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
min-width: 1100px;
}
thead th {
background:
linear-gradient(180deg,
#fff5f5,
#ffeaea);
font-size: 14px;
color: #991b1b;
font-weight: 700;
padding: 16px 14px;
border-bottom: 1px solid #f0d4d4;
position: sticky;
top: 0;
z-index: 5;
box-shadow:
0 4px 10px rgba(15, 23, 42, .04);
letter-spacing: .2px;
}
tbody td {
padding: 15px 14px;
font-size: 14px;
border-bottom: 1px solid #f3f4f6;
color: #374151;
}
tbody tr:nth-child(even) {
background: #fafafa;
}
tbody tr {
transition: .2s;
}
tbody tr:hover {
background:
linear-gradient(90deg,
rgba(255, 245, 245, .9),
rgba(255, 255, 255, .95));
}
.badge {
padding: 7px 12px;
border-radius: 8px;
font-size: 11px;
font-weight: 700;
background:
linear-gradient(135deg,
#fff1f1,
#ffdede);
color: #991b1b;
border: 1px solid #f4b4b4;
letter-spacing: .3px;
}
.action-btn {
background: var(--primary);
border: 1px solid var(--primary);
color: #fff;
padding: 6px 12px;
border-radius: 6px;
font-size: 12px;
transition: .2s;
}
.action-btn:hover {
background: transparent;
border: 1px solid var(--primary);
color: var(--primary);
}
.footer {
flex-shrink: 0;
color: #ebebeb;
font-size: 14px;
padding: 16px 22px;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #c2c2c2;
background-color: #d32f2f;
}
.pagination {
display: flex;
align-items: center;
gap: 8px;
}
.page-btn {
width: 34px;
height: 34px;
border: none;
border-radius: 6px;
background: #ffffff;
cursor: pointer;
font-size: 13px;
}
.page-btn.active {
background: #760006;
border: 1px solid #9a0007;
color: #fff;
transition: all .22s ease;
}
.page-btn:hover {
transform: translateY(-2px);
box-shadow: 0 14px 24px rgba(211, 47, 47, 0.28);
}
thead th:nth-child(2),
thead th:nth-child(6),
thead th:nth-child(3) {
text-align: left;
}
tbody td:nth-child(1),
tbody td:nth-child(4),
tbody td:nth-child(5),
tbody td:nth-child(7) {
text-align: center;
}
thead th:nth-child(1),
thead th:nth-child(4),
thead th:nth-child(5),
thead th:nth-child(7) {
text-align: center;
}
.swal-popup {
border-radius: 18px;
padding: 25px;
font-family: Poppins, sans-serif;
box-shadow: 0 20px 45px rgba(0, 0, 0, 0.18);
}
.swal-title {
font-size: 20px;
font-weight: 700;
color: #1f2937;
}
.swal2-html-container,
.swal2-text {
font-size: 14px !important;
}
.swal-btn,
.swal-btn-danger,
.swal-btn-cancel {
border: none !important;
border-radius: 10px !important;
padding: 10px 22px !important;
font-size: 14px !important;
font-weight: 600 !important;
transition: .25s ease;
}
.swal-btn {
background:
linear-gradient(135deg,
#34d399 0%,
#10b981 45%,
#059669 100%);
}
.swal-btn:hover {
transform: translateY(-2px);
box-shadow:
0 12px 22px rgba(16, 185, 129, 0.38),
inset 0 1px 1px rgba(255, 255, 255, 0.3);
}
.swal-btn-danger {
background:
linear-gradient(135deg,
#fb7185 0%,
#ef4444 45%,
#dc2626 100%);
box-shadow:
0 6px 14px rgba(239, 68, 68, 0.28),
inset 0 1px 1px rgba(255, 255, 255, 0.24);
}
.swal-btn-danger:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(211, 47, 47, .25);
box-shadow:
0 12px 22px rgba(239, 68, 68, 0.36),
inset 0 1px 1px rgba(255, 255, 255, 0.28);
}
.swal-btn-cancel {
background:
linear-gradient(135deg, #cbd5e1, #b6c4d3);
color: #1e293b;
border: 1px solid #aebdcd;
box-shadow:
0 10px 18px rgba(100, 116, 139, .22),
inset 0 1px 1px rgba(255, 255, 255, .65);
}
.swal-btn-cancel:hover {
background:
linear-gradient(135deg, #c6cfda, #afbbc9);
transform: translateY(-2px);
box-shadow:
0 14px 24px rgba(100, 116, 139, .28);
}
.table-wrap::-webkit-scrollbar {
width: 6px;
}
.table-wrap::-webkit-scrollbar-thumb {
background: #d32f2f;
border-radius: 10px;
}
/* =========================
RESPONSIVE BREAKPOINTS
========================= */
@media(max-width:768px) {
.module-nav {
grid-template-columns: 1fr;
}
}
@media (min-width: 1921px) {
.container {
max-width: 1800px;
margin: auto;
}
body {
padding: 40px;
}
.header {
font-size: 22px;
padding: 24px 36px;
}
table {
min-width: 100%;
}
}
@media (max-width: 1600px) {
table {
min-width: 1100px;
}
}
@media (max-width: 1366px) {
.toolbar {
gap: 14px;
}
.right-tools input {
width: 240px;
}
table {
min-width: 1000px;
}
}
@media (max-width: 1024px) {
body {
padding: 16px;
}
.toolbar {
flex-direction: column;
align-items: stretch;
}
.left-tools {
justify-content: flex-start;
}
.right-tools {
width: 100%;
align-items: stretch;
}
.filter-stack {
align-items: stretch;
}
.filter-row {
flex-wrap: wrap;
}
.search-box {
flex: 1;
min-width: 250px;
}
.search-box input {
width: 100%;
}
.month-filter {
width: 100%;
}
table {
min-width: 900px;
}
.table-wrap {
overflow-x: auto;
}
}
@media (max-width: 768px) {
body {
padding: 12px;
}
.header {
padding: 16px;
font-size: 16px;
}
.toolbar {
padding: 14px;
}
.filter-row {
flex-direction: column;
align-items: stretch;
}
.filter-toggle,
.print-btn {
width: 100%;
height: 44px;
}
.month-filter,
.search-box,
.search-box input {
width: 100%;
}
.left-tools {
flex-wrap: wrap;
gap: 8px;
}
.footer {
flex-direction: column;
gap: 12px;
text-align: center;
}
.pagination {
flex-wrap: wrap;
justify-content: center;
}
table {
min-width: 850px;
}
}
@media (max-width: 576px) {
body {
padding: 10px;
}
.card {
border-radius: 12px;
}
.header {
gap: 10px;
font-size: 15px;
padding: 14px;
}
.header i {
width: 34px;
height: 34px;
font-size: 14px;
}
.toolbar {
padding: 12px;
}
.left-tools {
justify-content: center;
}
.left-tools span {
font-size: 12px;
}
.left-tools select {
width: 60px;
}
.search-box input,
.month-filter {
height: 42px;
font-size: 12px;
}
.jenis-panel {
gap: 8px;
}
.jenis-chip {
width: 100%;
text-align: center;
}
.footer {
padding: 12px;
font-size: 12px;
}
.page-btn {
width: 32px;
height: 32px;
font-size: 12px;
}
}
@media (max-width: 480px) {
body {
padding: 8px;
}
.header {
font-size: 14px;
padding: 12px;
}
.header i {
width: 30px;
height: 30px;
font-size: 13px;
}
.toolbar {
padding: 10px;
}
.search-box input,
.month-filter {
font-size: 11px;
}
.badge {
padding: 5px 8px;
font-size: 10px;
}
.delete-btn {
width: 32px;
height: 32px;
}
tbody td {
padding: 12px 10px;
font-size: 12px;
}
thead th {
font-size: 12px;
padding: 12px 10px;
}
}
@media (max-width: 768px) {
.header {
flex-direction: column;
align-items: stretch;
}
.header-left {
justify-content: center;
}
.header-nav {
width: 100%;
display: grid;
grid-template-columns: 1fr;
gap: 8px;
}
.header-btn {
width: 100%;
box-sizing: border-box;
justify-content: left;
min-height: 44px;
}
}
@media (max-width: 360px) {
body {
padding: 6px;
}
.header {
font-size: 13px;
}
.left-tools {
flex-direction: column;
align-items: center;
}
.left-tools select {
width: 100%;
max-width: 100px;
}
.page-btn {
width: 28px;
height: 28px;
font-size: 11px;
}
.footer {
font-size: 11px;
}
}
@media (max-width: 1024px) {
.table-wrap {
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
}
.table-wrap::-webkit-scrollbar {
height: 6px;
}
.table-wrap::-webkit-scrollbar-thumb {
background: #d32f2f;
border-radius: 10px;
}
}
</style>
</head>
<body class="p-8">
@if (session('success'))
<script>
document.addEventListener("DOMContentLoaded", function() {
Swal.fire({
title: 'Berhasil!',
text: '{{ session('success') }}',
icon: 'success',
confirmButtonText: 'OK',
customClass: {
popup: 'swal-popup',
title: 'swal-title',
confirmButton: 'swal-btn'
}
});
});
</script>
@endif
<div class="w-full mx-auto">
{{-- <div class="container"> --}}
<div class="card">
<div class="header">
<div class="header-left">
<i class="fa-solid fa-clock-rotate-left"
style="background: linear-gradient(135deg, #d98a3d, #c97828);
width: 50px; height: 50px; font-size: 22px;"></i>
<span>DAFTAR RIWAYAT HASIL PREDIKSI</span>
</div>
<div class="header-nav">
<a href="/prediksi-barang" class="header-btn">
<i class="fa-solid fa-chart-column"></i>
Prediksi
</a>
<a href="/riwayat-prediksi" class="header-btn active">
<i class="fa-solid fa-clock-rotate-left"></i>
Riwayat
</a>
<a href="/rencana-pengadaan" class="header-btn">
<i class="fa-solid fa-boxes-stacked"></i>
Pengadaan
</a>
<button class="refresh-btn" onclick="location.reload()">
<i class="fa-solid fa-rotate-right refresh-icon"></i>
</button>
</div>
</div>
<div class="toolbar">
<div class="left-tools">
<span>Tampilkan</span>
<select>
<option>10</option>
<option>25</option>
<option>50</option>
<option>100</option>
</select>
<span>data</span>
</div>
<div class="right-tools">
<div class="filter-stack">
<div class="filter-row" style="display:flex; gap:12px; align-items:flex-start;">
<button class="filter-toggle" id="filterToggle">
<i class="fa-solid fa-sliders"></i>
</button>
<div style="position:relative;">
<i class="fa-solid fa-calendar-days month-icon"></i>
<input type="month" class="month-filter" id="monthFilter">
</div>
<div class="search-box">
<span class="search-icon">
<i class="fa-solid fa-magnifying-glass"></i>
</span>
<input type="text" placeholder="Cari kode / nama barang...">
</div>
<button class="print-btn" id="printPdfBtn">
<i class="fa-solid fa-print"></i>
</button>
</div>
<div class="jenis-panel" id="jenisPanel">
<button class="jenis-chip active semua-chip" data-jenis="">
Semua
</button>
@foreach ($jenisList as $jenis)
<button class="jenis-chip" data-jenis="{{ strtolower($jenis) }}">
{{ $jenis }}
</button>
@endforeach
</div>
</div>
</div>
</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>
Kode
<span class="sort-icons">
<i class="fa-solid fa-chevron-up"></i>
<i class="fa-solid fa-chevron-down"></i>
</span>
</th>
<th>
Nama Barang
<span class="sort-icons">
<i class="fa-solid fa-chevron-up"></i>
<i class="fa-solid fa-chevron-down"></i>
</span>
</th>
<th>
Jenis
<span class="sort-icons">
<i class="fa-solid fa-chevron-up"></i>
<i class="fa-solid fa-chevron-down"></i>
</span>
</th>
<th>
Hasil Prediksi
<span class="sort-icons">
<i class="fa-solid fa-chevron-up"></i>
<i class="fa-solid fa-chevron-down"></i>
</span>
</th>
<th>
Satuan
<span class="sort-icons">
<i class="fa-solid fa-chevron-up"></i>
<i class="fa-solid fa-chevron-down"></i>
</span>
</th>
<th>
Tanggal Prediksi
<span class="sort-icons">
<i class="fa-solid fa-chevron-up"></i>
<i class="fa-solid fa-chevron-down"></i>
</span>
</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
@foreach ($data as $row)
<tr data-bulan="{{ $row->bulan_prediksi }}" data-tahun="{{ $row->tahun_prediksi }}">
<td><span class="badge">{{ $row->kode }}</span></td>
<td>{{ $row->nama_barang }}</td>
<td>{{ $row->jenis }}</td>
<td>{{ number_format($row->jumlah_prediksi, 0, ',', '.') }}</td>
<td>{{ $row->satuan }}</td>
<td>{{ \Carbon\Carbon::parse($row->tanggal_prediksi)->format('d-m-Y') }}</td>
<td>
<form action="{{ route('riwayat-prediksi.destroy', $row->id) }}" method="POST"
class="form-hapus" style="display:inline;">
@csrf
@method('DELETE')
<button type="submit" class="delete-btn">
<i class="fa-solid fa-trash"></i>
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="footer">
<div></div>
<div class="pagination">
<button class="page-btn"></button>
<button class="page-btn active">1</button>
<button class="page-btn"></button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function() {
const table = document.querySelector("table");
const tbody = table.querySelector("tbody");
const headers = table.querySelectorAll("thead th");
const selectLimit = document.querySelector(".left-tools select");
const infoText = document.querySelector(".footer div");
const pagination = document.querySelector(".pagination");
const searchInput = document.querySelector(".search-box input");
const sortConfig = [{
index: 0,
type: "text"
},
{
index: 1,
type: "text"
},
{
index: 2,
type: "text"
},
{
index: 3,
type: "number"
},
{
index: 4,
type: "text"
},
{
index: 5,
type: "date"
}
];
const bulanMap = {
Januari: 1,
Februari: 2,
Maret: 3,
April: 4,
Mei: 5,
Juni: 6,
Juli: 7,
Agustus: 8,
September: 9,
Oktober: 10,
November: 11,
Desember: 12
};
let masterRows = Array.from(tbody.querySelectorAll("tr"));
let allRows = [...masterRows];
let currentPage = 1;
function getCellValue(row, index, type) {
let text = row.children[index].innerText.trim();
if (type === "number") return parseInt(text.replace(/\./g, "")) || 0;
if (type === "month") return bulanMap[text] || 0;
if (type === "date") {
let p = text.split("-");
return new Date(p[2], p[1] - 1, p[0]).getTime();
}
return text.toLowerCase();
}
function clearActive() {
document.querySelectorAll(".sort-icons i").forEach(i => {
i.classList.remove("active");
});
}
function renderTable() {
let perPage = parseInt(selectLimit.value);
let total = allRows.length;
let totalPages = Math.ceil(total / perPage);
if (totalPages < 1) totalPages = 1;
if (currentPage > totalPages) currentPage = 1;
let start = (currentPage - 1) * perPage;
let end = start + perPage;
tbody.innerHTML = "";
const rowsToShow = allRows.slice(start, end);
if (rowsToShow.length === 0) {
tbody.innerHTML = `
<tr>
<td colspan="7"
style="
text-align:center;
padding:40px 20px;
color:#9ca3af;
font-weight:600;
font-size:14px;
">
Tidak ada data
</td>
</tr>
`;
} else {
rowsToShow.forEach(row => {
tbody.appendChild(row);
});
}
let from = total === 0 ? 0 : start + 1;
let to = Math.min(end, total);
infoText.innerText = `Menampilkan ${from} sampai ${to} dari ${total} data`;
renderPagination(totalPages, total);
}
function renderPagination(totalPages, total) {
pagination.innerHTML = "";
if (total === 0) return;
const maxVisible = 5;
let prev = document.createElement("button");
prev.className = "page-btn";
prev.innerHTML = "";
prev.disabled = currentPage === 1;
prev.onclick = function() {
if (currentPage > 1) {
currentPage--;
renderTable();
}
};
pagination.appendChild(prev);
let startPage = Math.max(1, currentPage - 2);
let endPage = Math.min(totalPages, startPage + maxVisible - 1);
if (endPage - startPage < maxVisible - 1) {
startPage = Math.max(1, endPage - maxVisible + 1);
}
if (startPage > 1) {
addPageButton(1);
if (startPage > 2) {
addDots();
}
}
for (let i = startPage; i <= endPage; i++) {
addPageButton(i);
}
if (endPage < totalPages) {
if (endPage < totalPages - 1) {
addDots();
}
addPageButton(totalPages);
}
let next = document.createElement("button");
next.className = "page-btn";
next.innerHTML = "";
next.disabled = currentPage === totalPages;
next.onclick = function() {
if (currentPage < totalPages) {
currentPage++;
renderTable();
}
};
pagination.appendChild(next);
function addPageButton(page) {
let btn = document.createElement("button");
btn.className = "page-btn";
btn.innerText = page;
if (page === currentPage) {
btn.classList.add("active");
}
btn.onclick = function() {
currentPage = page;
renderTable();
};
pagination.appendChild(btn);
}
function addDots() {
let dots = document.createElement("span");
dots.innerText = "...";
dots.style.padding = "0 6px";
dots.style.fontWeight = "600";
dots.style.color = "#fff";
pagination.appendChild(dots);
}
}
selectLimit.addEventListener("change", function() {
currentPage = 1;
renderTable();
});
sortConfig.forEach(config => {
const th = headers[config.index];
const up = th.querySelector(".fa-chevron-up");
const down = th.querySelector(".fa-chevron-down");
if (!up || !down) return;
up.style.cursor = "pointer";
down.style.cursor = "pointer";
up.addEventListener("click", function() {
allRows.sort((a, b) => {
let valA = getCellValue(a, config.index, config.type);
let valB = getCellValue(b, config.index, config.type);
if (valA > valB) return 1;
if (valA < valB) return -1;
return 0;
});
clearActive();
up.classList.add("active");
currentPage = 1;
renderTable();
});
down.addEventListener("click", function() {
allRows.sort((a, b) => {
let valA = getCellValue(a, config.index, config.type);
let valB = getCellValue(b, config.index, config.type);
if (valA < valB) return 1;
if (valA > valB) return -1;
return 0;
});
clearActive();
down.classList.add("active");
currentPage = 1;
renderTable();
});
});
const forms = document.querySelectorAll(".form-hapus");
forms.forEach(form => {
form.addEventListener("submit", function(e) {
e.preventDefault();
Swal.fire({
title: 'Hapus Data?',
text: 'Data ini akan dihapus permanen.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Ya, Hapus',
cancelButtonText: 'Batal',
reverseButtons: true,
customClass: {
popup: 'swal-popup',
title: 'swal-title',
confirmButton: 'swal-btn-danger',
cancelButton: 'swal-btn-cancel'
}
}).then((result) => {
if (!result.isConfirmed) return;
fetch(form.action, {
method: "POST",
headers: {
"X-CSRF-TOKEN": document.querySelector(
'meta[name="csrf-token"]'
).content,
"X-Requested-With": "XMLHttpRequest"
},
body: new FormData(form)
})
.then(res => res.json())
.then(data => {
const row = form.closest("tr");
masterRows = masterRows.filter(r => r !== row);
allRows = allRows.filter(r => r !== row);
row.remove();
renderTable();
updatePrintButtonState();
Swal.fire({
title: 'Berhasil!',
text: data.message,
icon: 'success',
timer: 1800,
showConfirmButton: false,
customClass: {
popup: 'swal-popup',
title: 'swal-title'
}
});
});
});
});
});
const filterToggle = document.getElementById("filterToggle");
const jenisPanel = document.getElementById("jenisPanel");
const jenisChips = document.querySelectorAll(".jenis-chip");
const monthFilter = document.getElementById("monthFilter");
let selectedJenis = [];
let selectedMonth = "";
let availablePeriods = [];
availablePeriods = [
@foreach ($periodeList as $p)
"{{ $p->tahun_prediksi }}-{{ str_pad($p->bulan_prediksi, 2, '0', STR_PAD_LEFT) }}",
@endforeach
];
if (availablePeriods.length > 0) {
availablePeriods.sort();
monthFilter.min = availablePeriods[0];
monthFilter.max = availablePeriods[availablePeriods.length - 1];
const now = new Date();
const tahun = now.getFullYear();
const bulan = String(now.getMonth() + 1).padStart(2, "0");
const currentPeriod = tahun + "-" + bulan;
if (availablePeriods.includes(currentPeriod)) {
monthFilter.value = currentPeriod;
selectedMonth = currentPeriod;
}
}
filterToggle.addEventListener("click", function() {
jenisPanel.classList.toggle("show");
});
const semuaChip = document.querySelector(".semua-chip");
jenisChips.forEach(chip => {
chip.addEventListener("click", function() {
const jenis = this.dataset.jenis.toLowerCase();
if (jenis === "") {
selectedJenis = [];
jenisChips.forEach(btn => {
btn.classList.remove("active");
});
semuaChip.classList.add("active");
applyAllFilters();
return;
}
semuaChip.classList.remove("active");
this.classList.toggle("active");
if (selectedJenis.includes(jenis)) {
selectedJenis = selectedJenis.filter(item => item !== jenis);
} else {
selectedJenis.push(jenis);
}
if (selectedJenis.length === 0) {
semuaChip.classList.add("active");
}
applyAllFilters();
});
});
monthFilter.addEventListener("change", function() {
const selected = this.value;
if (!selected) {
selectedMonth = "";
applyAllFilters();
return;
}
const now = new Date();
const currentYear = now.getFullYear();
const currentMonth = now.getMonth() + 1;
const [year, month] = selected.split("-").map(Number);
const isFutureMonth =
year > currentYear ||
(year === currentYear && month > currentMonth);
if (isFutureMonth && !availablePeriods.includes(selected)) {
this.value = "";
selectedMonth = "";
return;
}
selectedMonth = selected;
applyAllFilters();
});
searchInput.addEventListener("keyup", function() {
applyAllFilters();
});
function updatePrintButtonState() {
const printBtn = document.getElementById("printPdfBtn");
if (allRows.length === 0) {
printBtn.disabled = true;
printBtn.classList.add("disabled");
} else {
printBtn.disabled = false;
printBtn.classList.remove("disabled");
}
}
function applyAllFilters() {
const keyword = searchInput.value.toLowerCase().trim();
allRows = masterRows.filter(row => {
const kode = row.children[0].innerText.toLowerCase();
const nama = row.children[1].innerText.toLowerCase();
const jenis = row.children[2].innerText.toLowerCase();
const bulan = row.dataset.bulan;
const tahun = row.dataset.tahun;
const periode = tahun + "-" + String(bulan).padStart(2, "0");
const cocokSearch =
kode.includes(keyword) || nama.includes(keyword);
const cocokJenis =
selectedJenis.length === 0 ||
selectedJenis.includes(jenis);
const cocokBulan =
selectedMonth === "" || periode === selectedMonth;
return cocokSearch && cocokJenis && cocokBulan;
});
currentPage = 1;
renderTable();
updatePrintButtonState();
}
applyAllFilters();
updatePrintButtonState();
const printPdfBtn = document.getElementById("printPdfBtn");
printPdfBtn.addEventListener("click", function() {
const params = new URLSearchParams();
if (selectedMonth) {
params.append("bulan", selectedMonth);
}
if (selectedJenis.length > 0) {
params.append("jenis", selectedJenis.join(","));
}
const keyword = searchInput.value.trim();
if (keyword !== "") {
params.append("search", keyword);
}
window.open(
`/riwayat-prediksi/cetak/pdf?${params.toString()}`,
"_blank"
);
});
});
</script>
</body>
</html>