399 lines
14 KiB
PHP
399 lines
14 KiB
PHP
@extends('layouts.dashboard')
|
|
|
|
@section('content')
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght=400;500;600;700;800&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
|
|
|
<style>
|
|
html, body {
|
|
-ms-overflow-style: none; /* IE and Edge */
|
|
scrollbar-width: none; /* Firefox */
|
|
}
|
|
.pending-wrapper {
|
|
font-family: 'Inter', sans-serif;
|
|
background-color: #f8fafc;
|
|
min-height: 80vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 20px;
|
|
}
|
|
|
|
.pending-card {
|
|
max-width: 600px;
|
|
width: 100%;
|
|
background: white;
|
|
border-radius: 24px;
|
|
padding: 50px 40px;
|
|
text-align: center;
|
|
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.05);
|
|
border: 1px solid #e2e8f0;
|
|
animation: scaleIn 0.5s ease-out;
|
|
}
|
|
|
|
@keyframes scaleIn {
|
|
from { opacity: 0; transform: scale(0.9); }
|
|
to { opacity: 1; transform: scale(1); }
|
|
}
|
|
|
|
/* ==========================================================================
|
|
ICON BOXES (WARNA & ANIMASI BERDASARKAN STATUS)
|
|
========================================================================== */
|
|
.icon-box {
|
|
width: 100px;
|
|
height: 100px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 40px;
|
|
border-radius: 50%;
|
|
margin: 0 auto 30px;
|
|
}
|
|
|
|
/* 1. Pending (Kuning) */
|
|
.icon-box.status-pending {
|
|
background: #fef3c7;
|
|
color: #d97706;
|
|
animation: pulse-amber 2s infinite;
|
|
}
|
|
@keyframes pulse-amber {
|
|
0% { box-shadow: 0 0 0 0 rgba(217, 119, 6, 0.2); }
|
|
70% { box-shadow: 0 0 0 20px rgba(217, 119, 6, 0); }
|
|
100% { box-shadow: 0 0 0 0 rgba(217, 119, 6, 0); }
|
|
}
|
|
|
|
/* 2. Ditolak (Merah) */
|
|
.icon-box.status-rejected {
|
|
background: #fee2e2;
|
|
color: #dc2626;
|
|
}
|
|
|
|
/* 3. Disetujui (Hijau) */
|
|
.icon-box.status-approved {
|
|
background: #dcfce7;
|
|
color: #16a34a;
|
|
animation: pulse-green 2s infinite;
|
|
}
|
|
@keyframes pulse-green {
|
|
0% { box-shadow: 0 0 0 0 rgba(22, 163, 74, 0.2); }
|
|
70% { box-shadow: 0 0 0 20px rgba(22, 163, 74, 0); }
|
|
100% { box-shadow: 0 0 0 0 rgba(22, 163, 74, 0); }
|
|
}
|
|
|
|
|
|
/* ==========================================================================
|
|
BADGES (LABEL STATUS)
|
|
========================================================================== */
|
|
.status-badge {
|
|
padding: 6px 16px;
|
|
border-radius: 100px;
|
|
font-size: 0.8rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
margin-bottom: 20px;
|
|
display: inline-block;
|
|
}
|
|
.status-badge.status-pending {
|
|
background: #fff7ed;
|
|
color: #c2410c;
|
|
}
|
|
.status-badge.status-rejected {
|
|
background: #fef2f2;
|
|
color: #991b1b;
|
|
}
|
|
.status-badge.status-approved {
|
|
background: #f0fdf4;
|
|
color: #166534;
|
|
}
|
|
|
|
|
|
/* ==========================================================================
|
|
INFO BOXES (KOTAK DETAIL)
|
|
========================================================================== */
|
|
.info-box {
|
|
border-radius: 12px;
|
|
padding: 20px;
|
|
text-align: left;
|
|
margin-bottom: 30px;
|
|
}
|
|
.info-box.status-pending {
|
|
background: #f1f5f9;
|
|
}
|
|
.info-box.status-rejected {
|
|
background: #fff5f5;
|
|
border-left: 4px solid #f87171;
|
|
}
|
|
.info-box.status-approved {
|
|
background: #f0fdf4;
|
|
border-left: 4px solid #4ade80;
|
|
}
|
|
|
|
.pending-card h2 {
|
|
color: #1e293b;
|
|
font-weight: 800;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.pending-card p {
|
|
color: #64748b;
|
|
line-height: 1.6;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.info-item {
|
|
display: flex;
|
|
gap: 12px;
|
|
margin-bottom: 10px;
|
|
font-size: 0.9rem;
|
|
}
|
|
.info-item:last-child { margin-bottom: 0; }
|
|
|
|
|
|
/* ==========================================================================
|
|
ACTION BUTTONS (TOMBOL AKSI)
|
|
========================================================================== */
|
|
.action-group {
|
|
display: flex;
|
|
gap: 12px;
|
|
justify-content: center;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.btn-action {
|
|
text-decoration: none;
|
|
padding: 14px 26px;
|
|
border-radius: 12px;
|
|
font-weight: 600;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
transition: 0.3s;
|
|
font-size: 0.95rem;
|
|
}
|
|
|
|
/* Tombol Merah (Daftar Ulang) */
|
|
.btn-danger-action {
|
|
background: #dc2626;
|
|
color: white;
|
|
}
|
|
.btn-danger-action:hover {
|
|
background: #b91c1c;
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 10px 15px -3px rgba(220, 38, 38, 0.3);
|
|
}
|
|
|
|
/* Tombol Putih/Abu (Hubungi Admin) */
|
|
.btn-secondary-action {
|
|
background: white;
|
|
color: #475569;
|
|
border: 1px solid #cbd5e1;
|
|
}
|
|
.btn-secondary-action:hover {
|
|
background: #f8fafc;
|
|
color: #1e293b;
|
|
border-color: #94a3b8;
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
/* Tombol Hijau (Masuk Dashboard) */
|
|
.btn-success-action {
|
|
background: #16a34a;
|
|
color: white;
|
|
}
|
|
.btn-success-action:hover {
|
|
background: #15803d;
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 10px 15px -3px rgba(22, 163, 74, 0.3);
|
|
}
|
|
</style>
|
|
|
|
<div class="pending-wrapper">
|
|
<div class="pending-card">
|
|
|
|
{{-- ================= Kondisi 1: DITOLAK ================= --}}
|
|
@if($anggota->status == 'ditolak')
|
|
|
|
<div class="icon-box status-rejected">
|
|
<i class="fas fa-user-times"></i>
|
|
</div>
|
|
|
|
<span class="status-badge status-rejected">Pendaftaran Ditolak</span>
|
|
|
|
<h2>Status Anggota Ditolak</h2>
|
|
|
|
<p>Halo, <strong>{{ Auth::user()->name }}</strong>.Pendaftaran ditolak karena data atau dokumen yang diunggah belum memenuhi persyaratan, dokumen pendukung yang tidak sesuai, foto identitas yang kurang jelas, atau informasi yang tidak dapat diverifikasi.</p>
|
|
|
|
<div class="info-box status-rejected">
|
|
<div class="info-item" style="color: #7f1d1d;">
|
|
<i class="fas fa-exclamation-circle mt-1 text-danger"></i>
|
|
<span>Silakan <strong>cek kembali data diri Anda</strong>, pastikan seluruh berkas valid, lalu daftarkan ulang profil Anda.</span>
|
|
</div>
|
|
<div class="info-item" style="color: #7f1d1d;">
|
|
<i class="fas fa-comments mt-1 text-danger"></i>
|
|
<span>Jika ada pertanyaan, Anda dapat langsung menghubungi admin via tombol di bawah ini.</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="action-group">
|
|
<!-- Diarahkan ke form pembuatan/pengisian data awal -->
|
|
<a href="{{ route('user.member.create') }}" class="btn-action btn-danger-action">
|
|
<i class="fas fa-user-edit"></i> Cek Data & Daftar Ulang
|
|
</a>
|
|
<a href="https://wa.me/081229523471" target="_blank" class="btn-action btn-secondary-action">
|
|
<i class="fab fa-whatsapp"></i> Hubungi Admin
|
|
</a>
|
|
</div>
|
|
|
|
{{-- ================= Kondisi 2: DISETUJUI / AKTIF ================= --}}
|
|
@elseif($anggota->status == 'disetujui')
|
|
|
|
<div class="icon-box status-approved">
|
|
<i class="fas fa-user-check"></i>
|
|
</div>
|
|
|
|
<span class="status-badge status-approved">Akun Aktif</span>
|
|
|
|
<h2>Pendaftaran Disetujui!</h2>
|
|
|
|
<p>Selamat, <strong>{{ Auth::user()->name }}</strong>! Akun keanggotaan Anda telah berhasil diverifikasi oleh admin. Sekarang Anda memiliki akses penuh ke sistem.</p>
|
|
|
|
<div class="info-box status-approved">
|
|
<div class="info-item" style="color: #14532d;">
|
|
<i class="fas fa-check-circle mt-1 text-success"></i>
|
|
<span>Selamat bergabung! Silakan masuk ke dashboard utama untuk mulai menggunakan layanan keanggotaan.</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="action-group">
|
|
<a href="{{ route('user.peminjaman.index') }}" class="btn-action btn-success-action">
|
|
<i class="fas fa-tachometer-alt"></i> Masuk Ke Dashboard
|
|
</a>
|
|
</div>
|
|
|
|
{{-- ================= Kondisi 3: MENUNGGU VERIFIKASI (DEFAULT) ================= --}}
|
|
@else
|
|
|
|
<div class="icon-box status-pending">
|
|
<i class="fas fa-hourglass-half"></i>
|
|
</div>
|
|
|
|
<span class="status-badge status-pending">Menunggu Verifikasi</span>
|
|
|
|
<h2>Pendaftaran Terkirim!</h2>
|
|
|
|
<p>Halo, <strong>{{ Auth::user()->name }}</strong>. Data pendaftaran Anda telah kami terima. Saat ini admin sedang melakukan validasi berkas dan profil Anda.</p>
|
|
|
|
<div class="info-box status-pending">
|
|
<div class="info-item">
|
|
<i class="fas fa-info-circle mt-1 text-primary"></i>
|
|
<span>Proses verifikasi biasanya memakan waktu <strong>1-2 hari kerja</strong>.</span>
|
|
</div>
|
|
<div class="info-item">
|
|
<i class="fas fa-bell mt-1 text-primary"></i>
|
|
<span>Anda dapat memantau status keanggotaan Anda di halaman ini secara berkala.</span>
|
|
</div>
|
|
</div>
|
|
|
|
@endif
|
|
|
|
</div>
|
|
</div>
|
|
{{-- Letakkan kode ini di bagian paling bawah sebelum @endsection --}}
|
|
|
|
<!-- Tambahkan Pustaka MQTT.js via CDN (jika layout utama belum memuatnya) -->
|
|
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
|
|
|
|
<script>
|
|
// 1. Konfigurasi MQTT Broker menggunakan WebSocket (Port default Mosquitto WS biasanya 9001 atau 8083)
|
|
const mqttBrokerUrl = 'ws://127.0.0.1:9001';
|
|
const currentUserId = "{{ Auth::id() }}"; // Mengambil ID User yang sedang login
|
|
const mqttClientId = 'laravel_blade_user_' + currentUserId + '_' + Math.random().toString(16).substr(2, 4);
|
|
|
|
const mqttClient = mqtt.connect(mqttBrokerUrl, {
|
|
clientId: mqttClientId,
|
|
clean: true,
|
|
connectTimeout: 5000,
|
|
});
|
|
|
|
// 2. Tentukan Topik Berdasarkan User ID sesuai dengan yang di-publish oleh AnggotaController
|
|
const statusTopic = 'pendaftaran/status/' + currentUserId;
|
|
|
|
mqttClient.on('connect', () => {
|
|
console.log('User terhubung ke Real-time Server via MQTT WebSocket.');
|
|
|
|
mqttClient.subscribe(statusTopic, (err) => {
|
|
if (!err) {
|
|
console.log(`Sukses mendengarkan pembaruan pada topik: ${statusTopic}`);
|
|
}
|
|
});
|
|
});
|
|
|
|
mqttClient.on('message', (topic, message) => {
|
|
try {
|
|
const payload = JSON.parse(message.toString());
|
|
console.log("Pesan Status Diterima:", payload);
|
|
|
|
// 3. Tangani Perubahan Status secara Dinamis
|
|
if (payload.status === 'disetujui') {
|
|
// Skenario 1: Admin menyetujui, meminta user melakukan tap kartu RFID ke mesin IoT
|
|
showRealtimeToast(payload.message || "Pendaftaran disetujui! Silakan tap kartu Anda pada mesin RFID.");
|
|
|
|
// Berikan jeda 2.5 detik agar pengguna sempat membaca instruksi, lalu muat ulang halaman
|
|
setTimeout(() => {
|
|
window.location.reload();
|
|
}, 2500);
|
|
|
|
} else if (payload.status === 'uid_ready') {
|
|
// Skenario 2: User sukses melakukan tap kartu RFID di alat IoT dan UID tersimpan
|
|
showRealtimeToast(payload.message || "Kartu RFID berhasil diregistrasikan! Mengalihkan ke dashboard...");
|
|
|
|
// Otomatis arahkan user langsung menuju dashboard utama peminjaman setelah 2 detik
|
|
setTimeout(() => {
|
|
window.location.href = "{{ route('user.peminjaman.index') }}";
|
|
}, 2000);
|
|
|
|
} else if (payload.status === 'ditolak' || payload.status === 'deleted') {
|
|
// Skenario 3: Pendaftaran ditolak admin atau dihapus
|
|
showRealtimeToast(payload.message || "Status pendaftaran Anda diperbarui.", "#dc2626");
|
|
|
|
setTimeout(() => {
|
|
window.location.reload();
|
|
}, 2500);
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error("Gagal memproses payload pesan MQTT:", error);
|
|
}
|
|
});
|
|
|
|
mqttClient.on('error', (err) => {
|
|
console.error('Koneksi MQTT Interface Gagal: ', err);
|
|
});
|
|
|
|
// 4. Komponen Helper Pembuat Toast Notifikasi Melayang Dinamis
|
|
function showRealtimeToast(text, backgroundColor = '#16a34a') {
|
|
const toast = document.createElement('div');
|
|
toast.style.position = 'fixed';
|
|
toast.style.bottom = '30px';
|
|
toast.style.right = '30px';
|
|
toast.style.backgroundColor = backgroundColor;
|
|
toast.style.color = '#fff';
|
|
toast.style.padding = '16px 28px';
|
|
toast.style.borderRadius = '14px';
|
|
toast.style.boxShadow = '0 10px 25px -5px rgba(0,0,0,0.15)';
|
|
toast.style.zIndex = '99999';
|
|
toast.style.fontFamily = "'Inter', sans-serif";
|
|
toast.style.fontWeight = '600';
|
|
toast.style.fontSize = '0.95rem';
|
|
toast.style.transition = 'all 0.4s ease';
|
|
|
|
// Menambahkan ikon lonceng kecil di depan teks
|
|
toast.innerHTML = `<i class="fas fa-bell animate-bounce mr-2"></i> ${text}`;
|
|
|
|
document.body.appendChild(toast);
|
|
}
|
|
</script>
|
|
@endsection
|
|
|