<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sistem Monitoring Siklus Menstruasi - SMPN 2 Tarik</title>
<style>
/* Desain Tema Warna Baru: Merah, Pink, dan Hitam */
:root {
--bg-color: #FFF0F2; /* Warna latar belakang pink sangat muda */
--card-bg: #FFFFFF;
--primary: #FF4D6D; /* Warna pink kemerahan cerah */
--primary-hover: #E01E37; /* Warna merah tegas */
--secondary: #1A1A1A; /* Warna hitam legam untuk elemen gelap */
--accent: #FF85A1; /* Warna pink aksen */
--text-main: #1A1A1A; /* Warna teks utama hitam */
--text-muted: #666666; /* Warna teks sekunder abu-abu gelap */
--border-color: #FFCCD5; /* Warna garis tepi pink pastel */
--success: #CCFFD3;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: var(--bg-color);
color: var(--text-main);
padding: 20px;
line-height: 1.6;
}
.container {
max-width: 1100px;
margin: 0 auto;
}
header {
background: linear-gradient(135deg, var(--secondary), var(--primary));
padding: 25px;
border-radius: 20px;
text-align: center;
margin-bottom: 25px;
box-shadow: 0 8px 20px rgba(255, 77, 109, 0.2);
color: #FFFFFF;
}
header h1 {
font-size: 26px;
margin-bottom: 6px;
}
header p {
font-size: 14px;
opacity: 0.9;
letter-spacing: 0.5px;
}
.grid {
display: grid;
grid-template-columns: 1fr;
gap: 25px;
}
@media (min-width: 768px) {
.grid {
grid-template-columns: 1fr 1.2fr;
}
}
.card {
background: var(--card-bg);
padding: 25px;
border-radius: 20px;
box-shadow: 0 8px 24px rgba(255, 77, 109, 0.1);
border: 1px solid var(--border-color);
height: fit-content;
}
.card h2 {
font-size: 18px;
margin-bottom: 20px;
color: var(--secondary);
display: flex;
align-items: center;
gap: 10px;
border-bottom: 2px dashed var(--border-color);
padding-bottom: 10px;
}
.form-group {
margin-bottom: 16px;
}
.form-group label {
display: block;
margin-bottom: 6px;
font-weight: 600;
font-size: 14px;
color: #333333;
}
.form-control {
width: 100%;
padding: 12px 15px;
border: 2px solid var(--border-color);
border-radius: 12px;
font-size: 14px;
background-color: #FFFFFF;
color: var(--text-main);
transition: all 0.3s ease;
}
.form-control:focus {
outline: none;
border-color: var(--primary);
background-color: #FFFFFF;
box-shadow: 0 0 8px rgba(255, 77, 109, 0.3);
}
.btn {
display: inline-block;
width: 100%;
padding: 12px;
border: none;
border-radius: 12px;
font-size: 15px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
text-align: center;
}
.btn-primary {
background-color: var(--primary);
color: #FFFFFF;
box-shadow: 0 4px 12px rgba(255, 77, 109, 0.3);
}
.btn-primary:hover {
background-color: var(--primary-hover);
transform: translateY(-1px);
}
.btn-secondary {
background-color: var(--border-color);
color: var(--secondary);
box-shadow: 0 4px 12px rgba(255, 204, 213, 0.4);
}
.btn-secondary:hover {
background-color: var(--accent);
transform: translateY(-1px);
}
.btn-danger {
background-color: #FFB3B3;
color: #602020;
padding: 8px 12px;
font-size: 13px;
border-radius: 10px;
}
.btn-danger:hover {
background-color: #FFA1A1;
}
.table-responsive {
width: 100%;
overflow-x: auto;
margin-top: 15px;
}
table {
width: 100%;
border-collapse: collapse;
text-align: left;
font-size: 14px;
}
th, td {
padding: 12px 15px;
border-bottom: 1px solid var(--border-color);
}
th {
background-color: #FFE5EC;
color: var(--secondary);
font-weight: 600;
}
tr:hover {
background-color: #FFF5F6;
}
.empty-state {
text-align: center;
padding: 30px;
color: var(--text-muted);
font-style: italic;
}
.profile-summary {
background: linear-gradient(135deg, #FFE5EC, #FFF0F2);
padding: 15px;
border-radius: 12px;
margin-bottom: 20px;
border-left: 5px solid var(--primary);
color: var(--text-main);
}
.profile-summary p {
font-size: 14px;
margin-bottom: 5px;
}
.profile-summary p strong {
color: var(--secondary);
}
.alert-box {
background-color: #FFD6BA;
color: #7A3E16;
padding: 12px;
border-radius: 12px;
margin-bottom: 20px;
font-size: 14px;
display: none;
text-align: center;
animation: fadeIn 0.5s;
}
@media (prefers-reduced-motion: no-preference) {
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>🌸 Buku Saku Si-Siklus SMPN 2 Tarik</h1>
<p>Aplikasi Pengisian & Monitoring Siklus Menstruasi Siswi Bulanan</p>
</header>
<div class="alert-box" id="alertBox">Data berhasil disimpan!</div>
<div class="grid">
<!-- Kolom Kiri: Form Identitas & Input Tanggal Harian -->
<div>
<!-- Card 1: Identitas Siswa -->
<div class="card" style="margin-bottom: 25px;">
<h2>📝 Data Identitas Siswi</h2>
<form id="profileForm">
<div class="form-group">
<label for="namaSiswa">Nama Lengkap Siswa</label>
<input type="text" id="namaSiswa" class="form-control" placeholder="Masukkan nama lengkap siswi" required>
</div>
<div class="form-group">
<label for="kelasSiswa">Kelas</label>
<select id="kelasSiswa" class="form-control" required>
<option value="">-- Pilih Kelas --</option>
<!-- Opsi Kelas 7 (7-1 sampai 7-8) -->
<option value="7-1">Kelas 7-1</option>
<option value="7-2">Kelas 7-2</option>
<option value="7-3">Kelas 7-3</option>
<option value="7-4">Kelas 7-4</option>
<option value="7-5">Kelas 7-5</option>
<option value="7-6">Kelas 7-6</option>
<option value="7-7">Kelas 7-7</option>
<option value="7-8">Kelas 7-8</option>
<!-- Opsi Kelas 8 (8-1 sampai 8-8) -->
<option value="8-1">Kelas 8-1</option>
<option value="8-2">Kelas 8-2</option>
<option value="8-3">Kelas 8-3</option>
<option value="8-4">Kelas 8-4</option>
<option value="8-5">Kelas 8-5</option>
<option value="8-6">Kelas 8-6</option>
<option value="8-7">Kelas 8-7</option>
<option value="8-8">Kelas 8-8</option>
<!-- Opsi Kelas 9 (9-1 sampai 9-8) -->
<option value="9-1">Kelas 9-1</option>
<option value="9-2">Kelas 9-2</option>
<option value="9-3">Kelas 9-3</option>
<option value="9-4">Kelas 9-4</option>
<option value="9-5">Kelas 9-5</option>
<option value="9-6">Kelas 9-6</option>
<option value="9-7">Kelas 9-7</option>
<option value="9-8">Kelas 9-8</option>
</select>
</div>
<div class="form-group">
<label for="noAbsen">Nomor Absen</label>
<input type="number" id="noAbsen" class="form-control" min="1" max="32" placeholder="Contoh: 12 (Maksimal 32)" required>
</div>
<div class="form-group">
<label for="tglMulai">Tanggal Mulai Menstruasi (Hari Pertama)</label>
<input type="date" id="tglMulai" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Simpan Profil Siswi</button>
</form>
</div>
<!-- Card 2: Pengisian Harian -->
<div class="card">
<h2>📅 Pengisian Tanggal Menstruasi Setiap Hari</h2>
<div id="profileWarning" style="color: var(--text-muted); font-size: 13px; font-style: italic;">
⚠️ Mohon isi dan simpan data "Identitas Siswi" di atas terlebih dahulu agar dapat mengaktifkan form pengisian harian ini.
</div>
<form id="dailyForm" style="display: none;">
<div class="form-group">
<label for="tglHarian">Pilih Tanggal Menstruasi Aktif</label>
<input type="date" id="tglHarian" class="form-control" required>
</div>
<div class="form-group">
<label for="kondisiFluks">Kondisi Aliran Aliran Darah</label>
<select id="kondisiFluks" class="form-control">
<option value="Normal / Sedang">Normal / Sedang</option>
<option value="Banyak">Banyak</option>
<option value="Sedikit (Flek)">Sedikit (Flek)</option>
</select>
</div>
<button type="submit" class="btn btn-primary" style="background: linear-gradient(135deg, var(--accent), var(--primary)); color: #FFFFFF;">Catat Tanggal Hari Ini</button>
</form>
</div>
</div>
<!-- Kolom Kanan: Dashboard Tabel Hasil Monitoring -->
<div>
<div class="card" style="width: 100%;">
<h2>📊 Lembar Hasil Monitoring</h2>
<!-- Ringkasan Informasi Profil Aktif -->
<div id="activeProfileBox" class="profile-summary" style="display: none;">
<p><strong>Nama Siswi:</strong> <span id="summaryNama">-</span></p>
<p><strong>Kelas / No. Absen:</strong> <span id="summaryKelas">-</span> / No. <span id="summaryAbsen">-</span></p>
<p><strong>Tanggal Mulai Siklus:</strong> <span id="summaryTglMulai">-</span></p>
</div>
<!-- Tabel Riwayat Hari Pengisian -->
<div class="table-responsive">
<table>
<thead>
<tr>
<th>Urutan Hari</th>
<th>Tanggal Menstruasi</th>
<th>Kondisi</th>
<th style="text-align: center;">Tindakan</th>
</tr>
</thead>
<tbody id="logTableBody">
<tr>
<td colspan="4" class="empty-state">Belum ada data jurnal harian yang dimasukkan.</td>
</tr>
</tbody>
</table>
</div>
<!-- Tombol Aksi Download Laporan -->
<div style="margin-top: 25px; display: flex; flex-direction: column; gap: 10px;">
<button id="btnDownload" class="btn btn-secondary">📥 Unduh Hasil Monitoring (CSV)</button>
<button id="btnClear" class="btn btn-danger" style="display: none; width: 100%;">🗑️ Atur Ulang & Bersihkan Semua Data</button>
</div>
</div>
</div>
</div>
</div>
<script>
// State Penyimpanan Data Sementara Aplikasi
let trackingData = {
profile: null,
logs: []
};
// Sinkronisasi Komponen DOM
const profileForm = document.getElementById('profileForm');
const dailyForm = document.getElementById('dailyForm');
const profileWarning = document.getElementById('profileWarning');
const activeProfileBox = document.getElementById('activeProfileBox');
const logTableBody = document.getElementById('logTableBody');
const btnDownload = document.getElementById('btnDownload');
const btnClear = document.getElementById('btnClear');
const alertBox = document.getElementById('alertBox');
// Memuat ulang data dari LocalStorage jika browser di-refresh
window.addEventListener('DOMContentLoaded', () => {
const stored = localStorage.getItem('smpn2tarik_menstruasi');
if (stored) {
trackingData = JSON.parse(stored);
sinkronisasiUI();
}
});
// Proses Pengisian Profil Identitas
profileForm.addEventListener('submit', (e) => {
e.preventDefault();
trackingData.profile = {
nama: document.getElementById('namaSiswa').value,
kelas: document.getElementById('kelasSiswa').value,
absen: document.getElementById('noAbsen').value,
tglMulai: document.getElementById('tglMulai').value
};
saveData();
sinkronisasiUI();
tampilkanNotifikasi('Profil identitas siswi berhasil disimpan!');
});
// Proses Penambahan Tanggal Menstruasi Harian
dailyForm.addEventListener('submit', (e) => {
e.preventDefault();
const tglDipilih = document.getElementById('tglHarian').value;
const fluks = document.getElementById('kondisiFluks').value;
// Validasi agar tanggal tidak ganda/double input
const cekDuplikat = trackingData.logs.some(item => item.tanggal === tglDipilih);
if (cekDuplikat) {
alert('Tanggal ini sudah dimasukkan ke dalam daftar monitoring sebelumnya.');
return;
}
trackingData.logs.push({
tanggal: tglDipilih,
kondisi: fluks
});
// Urutkan tanggal dari yang terlama ke terbaru otomatis
trackingData.logs.sort((a, b) => new Date(a.tanggal) - new Date(b.tanggal));
saveData();
sinkronisasiUI();
document.getElementById('tglHarian').value = '';
tampilkanNotifikasi('Catatan tanggal harian berhasil ditambahkan!');
});
// Menghapus data baris tertentu
window.hapusBarisLog = function(index) {
if (confirm('Hapus catatan tanggal menstruasi pada hari ini?')) {
trackingData.logs.splice(index, 1);
saveData();
sinkronisasiUI();
tampilkanNotifikasi('Baris riwayat berhasil dihapus.');
}
};
// Bersihkan semua data instan
btnClear.addEventListener('click', () => {
if (confirm('Apakah Anda yakin ingin menghapus seluruh data profil dan riwayat monitoring? Data yang hilang tidak dapat dikembalikan.')) {
localStorage.removeItem('smpn2tarik_menstruasi');
trackingData = { profile: null, logs: [] };
profileForm.reset();
sinkronisasiUI();
tampilkanNotifikasi('Seluruh pangkalan data berhasil dibersihkan.');
}
});
// Fungsi Pembantu Manajemen Data
function saveData() {
localStorage.setItem('smpn2tarik_menstruasi', JSON.stringify(trackingData));
}
function tampilkanNotifikasi(pesan) {
alertBox.textContent = pesan;
alertBox.style.display = 'block';
setTimeout(() => {
alertBox.style.display = 'none';
}, 3000);
}
function ubahFormatTanggalIndo(teksTanggal) {
if (!teksTanggal) return '-';
const opsi = { year: 'numeric', month: 'long', day: 'numeric' };
return new Date(teksTanggal).toLocaleDateString('id-ID', opsi);
}
// Pembaruan Tampilan Antarmuka (UI) secara Real-Time
function sinkronisasiUI() {
if (trackingData.profile) {
// Isi form dengan data yang telah tersimpan
document.getElementById('namaSiswa').value = trackingData.profile.nama;
document.getElementById('kelasSiswa').value = trackingData.profile.kelas;
document.getElementById('noAbsen').value = trackingData.profile.absen;
document.getElementById('tglMulai').value = trackingData.profile.tglMulai;
// Tampilkan akses pengisian harian & ringkasan hasil
dailyForm.style.display = 'block';
profileWarning.style.display = 'none';
activeProfileBox.style.display = 'block';
btnDownload.style.display = 'block';
btnClear.style.display = 'block';
// Masukkan data ke kotak ringkasan profil
document.getElementById('summaryNama').textContent = trackingData.profile.nama;
document.getElementById('summaryKelas').textContent = trackingData.profile.kelas;
document.getElementById('summaryAbsen').textContent = trackingData.profile.absen;
document.getElementById('summaryTglMulai').textContent = ubahFormatTanggalIndo(trackingData.profile.tglMulai);
} else {
dailyForm.style.display = 'none';
profileWarning.style.display = 'block';
activeProfileBox.style.display = 'none';
btnDownload.style.display = 'none';
btnClear.style.display = 'none';
}
// Render data baris tabel riwayat harian
if (trackingData.logs.length === 0) {
logTableBody.innerHTML = `
<tr>
<td colspan="4" class="empty-state">Belum ada data jurnal harian yang dimasukkan.</td>
</tr>
`;
} else {
logTableBody.innerHTML = '';
trackingData.logs.forEach((item, idx) => {
const row = document.createElement('tr');
row.innerHTML = `
<td>Hari ke-${idx + 1}</td>
<td><b>${ubahFormatTanggalIndo(item.tanggal)}</b></td>
<td><span style="background-color: #FFE5EC; padding: 4px 10px; border-radius: 8px; border: 1px solid var(--border-color); font-size: 13px;">${item.kondisi}</span></td>
<td style="text-align: center;">
<button onclick="hapusBarisLog(${idx})" class="btn btn-danger" style="padding: 4px 8px; font-size: 12px;">Hapus</button>
</td>
`;
logTableBody.appendChild(row);
});
}
}
// Fungsi Utama Ekspor Hasil Monitoring Menjadi File Excel/CSV
btnDownload.addEventListener('click', () => {
if (!trackingData.profile) return;
// Inisialisasi format konten CSV dengan tanda BOM agar karakter bahasa Indonesia terbaca rapi di Excel
let isiCSV = "\uFEFF";
// Blok Informasi Header Laporan
isiCSV += "LAPORAN MONITORING SIKLUS MENSTRUASI SISWI - SMPN 2 TARIK\n";
isiCSV += `Waktu Unduh,${new Date().toLocaleString('id-ID')}\n\n`;
// Blok Identitas Siswi
isiCSV += "A. PROFIL SISWI\n";
isiCSV += `Nama Lengkap Siswa,${trackingData.profile.nama}\n`;
isiCSV += `Kelas,${trackingData.profile.kelas}\n`;
isiCSV += `Nomor Absen,${trackingData.profile.absen}\n`;
isiCSV += `Tanggal Mulai Menstruasi,${trackingData.profile.tglMulai}\n\n`;
// Blok Tabel Rekapan Bulanan/Harian
isiCSV += "B. JURNAL PENGISIAN TANGGAL MENSTRUASI HARIAN\n";
isiCSV += "No / Hari Ke,Tanggal Menstruasi,Kondisi Aliran\n";
if (trackingData.logs.length === 0) {
isiCSV += "Belum ada riwayat harian,-\n";
} else {
trackingData.logs.forEach((item, idx) => {
isiCSV += `Hari ke-${idx + 1},${item.tanggal},${item.kondisi}\n`;
});
}
// Pembuatan blob file virtual untuk memicu unduhan otomatis browser
const berkasBlob = new Blob([isiCSV], { type: 'text/csv;charset=utf-8;' });
const tautanUnduh = document.createElement("a");
const tautanUrl = URL.createObjectURL(berkasBlob);
// Berikan nama file aman yang dinamis berdasarkan nama siswi
const namaFileBebasSpasi = trackingData.profile.nama.toLowerCase().replace(/[^a-z0-9]/g, "_");
tautanUnduh.href = tautanUrl;
tautanUnduh.download = `monitoring_menstruasi_smpn2tarik_${namaFileBebasSpasi}.csv`;
tautanUnduh.style.visibility = 'hidden';
document.body.appendChild(tautanUnduh);
tautanUnduh.click();
document.body.removeChild(tautanUnduh);
});
</script>
</body>
</html>