Rabu, 15 Juli 2026

Belajar react 1

Baik. Saya akan mengajarkan React dengan pendekatan yang disesuaikan dengan pengalaman Anda sebagai programmer PHP. Jadi kita tidak mulai dari teori yang rumit, tetapi dengan membandingkannya dengan yang sudah Anda kuasai.

Rencana Belajar React

  1. ✅ Apa itu React
  2. ✅ Struktur proyek React
  3. ➜ JSX (pelajaran hari ini)
  4. Komponen
  5. Props
  6. State
  7. Event
  8. Form
  9. Routing
  10. React + Supabase

Pelajaran 1: JSX

JSX adalah cara menulis HTML di dalam JavaScript.

Misalnya di PHP Anda biasa menulis:

<h1>Assalamu'alaikum</h1>
<p>Selamat datang di Bimbel.</p>

Di React:

function App() {
  return (
    <div>
      <h1>Assalamu'alaikum</h1>
      <p>Selamat datang di Bimbel.</p>
    </div>
  );
}

Yang penting diperhatikan adalah:

return (
   ...
)

Artinya fungsi App() mengembalikan tampilan.


Kenapa harus ada <div>?

Di React, satu komponen harus mengembalikan satu elemen induk.

❌ Salah

return (
    <h1>Judul</h1>
    <p>Isi</p>
)

Karena ada dua elemen sejajar.

✅ Benar

return (
    <div>
        <h1>Judul</h1>
        <p>Isi</p>
    </div>
)

Menampilkan variabel

PHP:

<?php
$nama = "Abu Unais";
?>

<p><?= $nama ?></p>

React:

function App() {
    const nama = "Abu Unais";

    return (
        <p>{nama}</p>
    );
}

Di React, variabel ditampilkan dengan kurung kurawal {}.


Menampilkan hasil perhitungan

function App() {
    return (
        <h1>{10 + 5}</h1>
    );
}

Hasilnya:

15

Di dalam {} Anda bisa menulis ekspresi JavaScript.


Perbedaan dengan HTML

Ada beberapa perbedaan kecil.

HTML:

<label for="nama">Nama</label>

React:

<label htmlFor="nama">Nama</label>

Karena for adalah kata khusus di JavaScript.

Begitu juga:

HTML:

<input class="form-control">

React:

<input className="form-control" />

Menjadi className.


Tugas kecil

Buatlah komponen yang menampilkan:

Bismillah

Nama : Abu Unais
Usia : 40 Tahun
Pekerjaan : Programmer PHP

Gunakan:

  • const untuk menyimpan data.
  • {} untuk menampilkan variabel.

Tidak perlu khawatir jika salah. Justru dari latihan-latihan kecil seperti ini Anda akan cepat terbiasa membaca dan menulis kode React.

Besok atau setelah Anda selesai mencoba latihan ini, kita akan masuk ke komponen, yaitu konsep paling penting dalam React. Setelah memahami komponen, Anda akan mulai bisa membaca kode proyek Lovable yang sedang Anda kerjakan.

Minggu, 28 Juni 2026

test

Hadits yang Anda maksud diriwayatkan oleh Imam al-Bukhari dan Imam Muslim dari Hakim bin Hizam radhiyallahu 'anhu.

Dengan harakat:

عَنْ حَكِيمِ بْنِ حِزَامٍ رَضِيَ اللَّهُ عَنْهُ، عَنِ النَّبِيِّ ﷺ قَالَ:

«الْبَيِّعَانِ بِالْخِيَارِ مَا لَمْ يَتَفَرَّقَا، فَإِنْ صَدَقَا وَبَيَّنَا بُورِكَ لَهُمَا فِي بَيْعِهِمَا، وَإِنْ كَذَبَا وَكَتَمَا مُحِقَتْ بَرَكَةُ بَيْعِهِمَا.»

Terjemah:

Dari Hakim bin Hizam radhiyallahu 'anhu, dari Nabi ﷺ, beliau bersabda:

"Penjual dan pembeli masih memiliki hak memilih (melanjutkan atau membatalkan transaksi) selama mereka belum berpisah. Jika keduanya jujur dan menjelaskan (keadaan barang dengan apa adanya), niscaya keduanya akan diberi keberkahan dalam jual beli mereka. Namun jika keduanya berdusta dan menyembunyikan (cacat barang), maka dihapuslah keberkahan jual beli mereka."

Referensi:

  • Shahih al-Bukhari, no. 2079.
  • Shahih Muslim, no. 1532.

Hadits ini menjadi salah satu dalil utama dalam Islam bahwa kejujuran dan keterbukaan dalam muamalah merupakan sebab turunnya keberkahan, sedangkan kebohongan dan menyembunyikan cacat barang dapat menghilangkan keberkahan meskipun transaksi tersebut secara lahiriah menghasilkan keuntungan.

Jumat, 19 Juni 2026

floating windows

Jika yang Anda maksud adalah tombol ⋮ (three dots) yang ketika diklik muncul kotak menu mengambang seperti WhatsApp, Telegram, atau aplikasi mobile banking, maka Bootstrap 5 sudah menyediakan komponen Dropdown yang sangat cocok.

1. Tampilan Three Dot Vertikal

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css" rel="stylesheet">

<div class="dropdown">

    <button class="btn btn-light border-0"
            data-bs-toggle="dropdown">

        <i class="bi bi-three-dots-vertical"></i>

    </button>

    <ul class="dropdown-menu dropdown-menu-end shadow">

        <li>
            <a class="dropdown-item" href="#">
                <i class="bi bi-pencil me-2"></i>
                Edit
            </a>
        </li>

        <li>
            <a class="dropdown-item" href="#">
                <i class="bi bi-printer me-2"></i>
                Cetak
            </a>
        </li>

        <li>
            <a class="dropdown-item" href="#">
                <i class="bi bi-whatsapp me-2"></i>
                Kirim WA
            </a>
        </li>

        <li><hr class="dropdown-divider"></li>

        <li>
            <a class="dropdown-item text-danger" href="#">
                <i class="bi bi-trash me-2"></i>
                Hapus
            </a>
        </li>

    </ul>

</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>

Hasilnya:

      ⋮
      │
 ┌─────────────┐
 │ ✏ Edit      │
 │ 🖨 Cetak     │
 │ 📱 Kirim WA  │
 ├─────────────┤
 │ 🗑 Hapus     │
 └─────────────┘

2. Versi Lebih Elegan (Rounded & Floating)

Tambahkan CSS:

.dropdown-menu{
    border:none;
    border-radius:18px;
    padding:10px;
    min-width:220px;
    box-shadow:0 10px 30px rgba(0,0,0,.15);
}

.dropdown-item{
    border-radius:12px;
    padding:10px 14px;
}

.dropdown-item:hover{
    background:#f5f7fa;
}

Tampilannya mirip aplikasi mobile modern.


3. Floating Menu di Kartu Siswa

Contoh pada kartu siswa:

<div class="card shadow-sm rounded-4">

    <div class="card-body">

        <div class="d-flex justify-content-between">

            <div>
                <h5 class="mb-0">Ahmad Fauzan</h5>
                <small class="text-muted">
                    Tahsin A
                </small>
            </div>

            <div class="dropdown">

                <button
                    class="btn btn-light rounded-circle"
                    data-bs-toggle="dropdown">

                    <i class="bi bi-three-dots-vertical"></i>

                </button>

                <ul class="dropdown-menu dropdown-menu-end">

                    <li>
                        <a class="dropdown-item" href="#">
                            Detail
                        </a>
                    </li>

                    <li>
                        <a class="dropdown-item" href="#">
                            Edit
                        </a>
                    </li>

                    <li>
                        <a class="dropdown-item" href="#">
                            Kartu SPP
                        </a>
                    </li>

                    <li>
                        <a class="dropdown-item" href="#">
                            Pembayaran
                        </a>
                    </li>

                </ul>

            </div>

        </div>

    </div>

</div>

4. Floating Action Menu (Seperti Android)

Jika ingin benar-benar mengambang di kanan bawah layar:

<div class="dropup position-fixed bottom-0 end-0 m-4">

    <button class="btn btn-primary rounded-circle shadow"
            style="width:60px;height:60px"
            data-bs-toggle="dropdown">

        <i class="bi bi-three-dots fs-4"></i>

    </button>

    <ul class="dropdown-menu dropdown-menu-end shadow">

        <li><a class="dropdown-item" href="#">Tambah Siswa</a></li>
        <li><a class="dropdown-item" href="#">Tagihan Baru</a></li>
        <li><a class="dropdown-item" href="#">Laporan</a></li>

    </ul>

</div>

Tampilannya:

                   ┌──────────┐
                   │ Tambah   │
                   │ Tagihan  │
                   │ Laporan  │
                   └──────────┘

                        ●

Untuk aplikasi TPA/Bimbel yang sedang Anda buat, saya sarankan menggunakan Dropdown Bootstrap dengan dropdown-menu-end dan sudut membulat (rounded-4). Model ini paling mirip aplikasi profesional seperti Dana, BSI Mobile, atau MyTelkomsel, ringan, dan tidak perlu JavaScript tambahan selain Bootstrap.

Rabu, 17 Juni 2026

tampilkan pilihan

Masalahnya ada pada kondisi ini:

if($_GET['page']=='dataSiswa' or 'siswaNonAktif')

Bagian:

or 'siswaNonAktif'

selalu dianggap TRUE oleh PHP, sehingga kondisi menjadi tidak benar sesuai yang Anda inginkan.

Gunakan seperti ini:

<?php
if($_GET['page']=='dataSiswa' || $_GET['page']=='siswaNonAktif'){
?>
    <i class="bi bi-people text-primary"></i>
<?php
}else{
?>
    <i class="bi bi-people"></i>
<?php
}
?>

Atau yang lebih rapi:

<i class="bi bi-people <?=(isset($_GET['page']) && ($_GET['page']=='dataSiswa' || $_GET['page']=='siswaNonAktif')) ? 'text-primary' : '';?>"></i>

Sehingga menu Siswa akan berwarna biru ketika:

?page=dataSiswa

atau

?page=siswaNonAktif

Versi yang lebih aman

Untuk menghindari warning ketika $_GET['page'] belum ada:

<?php
$page = $_GET['page'] ?? '';

if(in_array($page,['dataSiswa','siswaNonAktif'])){
    echo '<i class="bi bi-people text-primary"></i>';
}else{
    echo '<i class="bi bi-people"></i>';
}
?>

Cara in_array() sangat cocok jika nanti submenu bertambah, misalnya:

in_array($page,[
    'dataSiswa',
    'siswaNonAktif',
    'siswaPindah',
    'siswaLulus'
])

jadi semua halaman yang berkaitan dengan siswa otomatis membuat ikon menu Siswa berwarna biru.

Minggu, 14 Juni 2026

Tanggal dengan rentang waktu tanpa submot

Bisa. Bahkan ini sangat umum digunakan pada dashboard laporan keuangan.

Caranya adalah membuat 2 input tanggal:

<div class="row">
    <div class="col-6">
        <input type="date" id="tgl_awal" class="form-control">
    </div>

    <div class="col-6">
        <input type="date" id="tgl_akhir" class="form-control">
    </div>
</div>

<div id="hasil"></div>

Javascript (Tanpa Submit)

Setiap kali salah satu tanggal berubah, data langsung diambil.

<script>

function loadData(){

    let awal  = document.getElementById('tgl_awal').value;
    let akhir = document.getElementById('tgl_akhir').value;

    if(awal && akhir){

        fetch(`laporan.php?awal=${awal}&akhir=${akhir}`)
        .then(response => response.text())
        .then(data => {

            document.getElementById('hasil').innerHTML = data;

        });

    }

}

document.getElementById('tgl_awal')
.addEventListener('change', loadData);

document.getElementById('tgl_akhir')
.addEventListener('change', loadData);

</script>

PHP

Misal file laporan.php

<?php

include 'koneksi.php';

$awal  = $_GET['awal'];
$akhir = $_GET['akhir'];

$query = mysqli_query($koneksi,"
SELECT *
FROM pembayaran
WHERE tanggal BETWEEN '$awal' AND '$akhir'
ORDER BY tanggal
");

while($row=mysqli_fetch_assoc($query)){

    echo "<div>";
    echo $row['tanggal']." - ";
    echo $row['nama']." - ";
    echo number_format($row['jumlah']);
    echo "</div>";

}

Untuk Dashboard Ringkasan

Misal Anda ingin otomatis mengubah:

  • Total pemasukan
  • Jumlah transaksi
  • Total tunggakan

Gunakan JSON.

PHP

<?php

include 'koneksi.php';

$awal  = $_GET['awal'];
$akhir = $_GET['akhir'];

$q = mysqli_query($koneksi,"
SELECT
SUM(jumlah) total,
COUNT(*) transaksi
FROM pembayaran
WHERE tanggal BETWEEN '$awal' AND '$akhir'
");

$data = mysqli_fetch_assoc($q);

echo json_encode($data);

Javascript

function loadData(){

    let awal  = $('#tgl_awal').val();
    let akhir = $('#tgl_akhir').val();

    if(awal && akhir){

        fetch(`summary.php?awal=${awal}&akhir=${akhir}`)
        .then(res => res.json())
        .then(data => {

            $('#total').html(
                'Rp ' + Number(data.total).toLocaleString('id-ID')
            );

            $('#transaksi').html(
                data.transaksi
            );

        });

    }
}

Lebih Elegan Lagi: Date Range Picker

Daripada dua input tanggal, gunakan satu input seperti:

01/06/2026 - 30/06/2026

Contohnya:

<input type="text" id="daterange" class="form-control">

Menggunakan plugin:

  • Date Range Picker
  • Flatpickr
  • Litepicker

Tampilannya seperti aplikasi kasir profesional dan laporan keuangan modern.

Contoh:

┌─────────────────────────┐
│ 📅 01 Jun - 30 Jun 2026 │
└─────────────────────────┘

Begitu rentang tanggal dipilih, AJAX langsung memuat ulang:

  • Ringkasan pemasukan
  • Grafik
  • Daftar pembayaran
  • Jumlah siswa yang membayar

tanpa tombol submit dan tanpa reload halaman. Ini adalah pola yang paling cocok untuk dashboard TPA/Bimbel yang sedang Anda bangun.

ganti data otomatis tanpa submit

Cara yang Anda inginkan adalah menggunakan AJAX atau Fetch API. Jadi ketika user mengganti tanggal pada <input type="date">, JavaScript langsung mengirim request ke PHP dan memperbarui data tanpa reload halaman dan tanpa tombol submit.

Contoh Sederhana

HTML

<input type="date" id="tanggal" class="form-control">

<div id="hasil">
    Silakan pilih tanggal
</div>

Javascript

<script>
document.getElementById('tanggal').addEventListener('change', function(){

    let tanggal = this.value;

    fetch('ambil_data.php?tanggal=' + tanggal)
    .then(response => response.text())
    .then(data => {

        document.getElementById('hasil').innerHTML = data;

    });

});
</script>

Ketika tanggal berubah, browser akan otomatis memanggil:

ambil_data.php?tanggal=2026-06-14

PHP (ambil_data.php)

<?php

$tanggal = $_GET['tanggal'];

include 'koneksi.php';

$query = mysqli_query($koneksi,"
SELECT *
FROM pembayaran
WHERE tanggal='$tanggal'
");

while($row = mysqli_fetch_assoc($query)){

    echo "<div>";
    echo $row['nama'];
    echo " - ";
    echo $row['jumlah'];
    echo "</div>";

}

Jika Menggunakan Bootstrap Card

Misal Anda punya ringkasan:

<div class="card">
    <div class="card-body">

        <h5>Total Pemasukan</h5>

        <h2 id="pemasukan">
            Rp0
        </h2>

    </div>
</div>

Javascript:

document.getElementById('tanggal').addEventListener('change', function(){

    let tanggal = this.value;

    fetch('summary.php?tanggal='+tanggal)
    .then(response => response.json())
    .then(data => {

        document.getElementById('pemasukan').innerHTML =
            'Rp' + Number(data.total).toLocaleString('id-ID');

    });

});

PHP:

<?php

$tanggal = $_GET['tanggal'];

include 'koneksi.php';

$q = mysqli_query($koneksi,"
SELECT SUM(jumlah) as total
FROM pembayaran
WHERE tanggal='$tanggal'
");

$data = mysqli_fetch_assoc($q);

echo json_encode($data);

Lebih Praktis dengan jQuery

Jika sudah menggunakan jQuery:

$('#tanggal').change(function(){

    let tanggal = $(this).val();

    $('#hasil').load(
        'ambil_data.php?tanggal='+tanggal
    );

});

Sangat singkat dan banyak dipakai di aplikasi admin.


Yang Paling Cocok Untuk Dashboard TPA Anda

Pada dashboard yang Anda buat:

  • User memilih tanggal.
  • Event change() terpanggil.
  • AJAX mengambil data:
    • Total pemasukan
    • Jumlah transaksi
    • Belum bayar
    • Daftar pembayaran
  • Card-card dashboard diperbarui otomatis.
  • Tidak ada tombol submit.
  • Tidak ada reload halaman.

Hasilnya terasa seperti aplikasi Android native meskipun hanya menggunakan PHP + Bootstrap 5.

Minggu, 07 Juni 2026

perbaikan

Pada script Anda sebenarnya sudah hampir benar. Yang perlu ditambahkan adalah:

  1. Preview foto harus memiliki id.
  2. Saat file dipilih, tampilkan preview.
  3. Upload otomatis menggunakan AJAX.
  4. Simpan path gambar ke database.
  5. Tidak perlu tombol upload.

1. Ubah bagian foto menjadi:

<div class="profile-wrapper">

    <img src="<?=$row['gambar'];?>"
         id="preview"
         class="profile-photo">

    <button type="button"
            class="camera-btn"
            onclick="document.getElementById('foto').click()">

        <i class="bi bi-camera-fill"></i>

    </button>

    <input type="file"
           id="foto"
           name="foto"
           accept="image/*"
           style="display:none;">

    <input type="hidden"
           id="id_siswa"
           value="<?=$idSiswa;?>">

</div>

<div id="uploadStatus"
     class="small mt-2 text-secondary">
</div>

2. Tambahkan script sebelum </body>

<script>

$('#foto').on('change', function(){

    let file = this.files[0];

    if(!file){
        return;
    }

    /*
    |--------------------------------------------------------------------------
    | Preview Langsung
    |--------------------------------------------------------------------------
    */
    let previewUrl = URL.createObjectURL(file);

    $('#preview').attr('src', previewUrl);

    $('#uploadStatus').html(
        '<span class="text-primary">Mengupload foto...</span>'
    );

    /*
    |--------------------------------------------------------------------------
    | Upload Otomatis
    |--------------------------------------------------------------------------
    */
    let formData = new FormData();

    formData.append('foto', file);
    formData.append(
        'id_siswa',
        $('#id_siswa').val()
    );

    $.ajax({

        url:'upload_foto_siswa.php',

        type:'POST',

        data:formData,

        contentType:false,

        processData:false,

        success:function(res){

            try{

                let data = JSON.parse(res);

                if(data.success){

                    $('#preview').attr(
                        'src',
                        data.url + '?t=' + Date.now()
                    );

                    $('#uploadStatus').html(
                        '<span class="text-success">✓ Foto berhasil diperbarui</span>'
                    );

                }else{

                    $('#uploadStatus').html(
                        '<span class="text-danger">Upload gagal</span>'
                    );

                }

            }catch(e){

                $('#uploadStatus').html(
                    '<span class="text-danger">Terjadi kesalahan</span>'
                );

            }

        }

    });

});

</script>

3. Buat file upload_foto_siswa.php

<?php

include "koneksi.php";

$response = [
    'success' => false
];

if(
    isset($_FILES['foto']) &&
    isset($_POST['id_siswa'])
){

    $id_siswa = $_POST['id_siswa'];

    $folder = "uploads/siswa/";

    if(!is_dir($folder)){
        mkdir($folder,0777,true);
    }

    $ext = strtolower(
        pathinfo(
            $_FILES['foto']['name'],
            PATHINFO_EXTENSION
        )
    );

    $namaFile =
        "siswa_" .
        $id_siswa .
        "_" .
        time() .
        "." .
        $ext;

    $path = $folder . $namaFile;

    if(
        move_uploaded_file(
            $_FILES['foto']['tmp_name'],
            $path
        )
    ){

        mysqli_query(
            $conn,
            "UPDATE tbl_siswa
             SET gambar='$path'
             WHERE id='$id_siswa'"
        );

        $response['success'] = true;
        $response['url'] = $path;

    }

}

echo json_encode($response);

Bonus (lebih elegan)

Tambahkan CSS berikut:

.camera-btn{
    position:absolute;
    right:5px;
    bottom:5px;
    width:42px;
    height:42px;
    border:none;
    border-radius:50%;
    background:#0d6efd;
    color:#fff;
    box-shadow:0 4px 10px rgba(0,0,0,.2);
}

.profile-wrapper{
    position:relative;
    width:140px;
    margin:auto;
}

Hasilnya akan seperti WhatsApp/Instagram:

  • Klik ikon kamera 📷
  • Pilih foto
  • Preview langsung berubah
  • Upload otomatis ke server
  • Database tbl_siswa.gambar langsung terupdate
  • Tidak ada tombol upload lagi.

 
Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | Press Release Distribution