Modul 03: Auth Helper & Reusable Layout

Modul 03: Auth Helper & Reusable Layout

Berikut adalah seluruh berkas kode program aktual yang digunakan dalam aplikasi SIPAS tanpa potongan atau placeholder. Kode dapat dipelajari dan diketikkan langsung pada Sublime Text 3.

1

Helper Otorisasi & Sesi (auth_helper.php)

Lokasi Berkas: application/helpers/auth_helper.php

application/helpers/auth_helper.php PHP
<?php
defined('BASEPATH') OR exit('No direct script access allowed');

/**
 * auth_helper.php
 * Helper untuk pengecekan session login dan role authorization
 */

if (!function_exists('is_logged_in')) {
    /**
     * Cek apakah user saat ini sedang login
     */
    function is_logged_in() {
        $CI =& get_instance();
        return (bool) $CI->session->userdata('logged_in');
    }
}

if (!function_exists('check_login')) {
    /**
     * Memastikan user sudah login, jika belum redirect ke /login
     */
    function check_login() {
        $CI =& get_instance();
        if (!$CI->session->userdata('logged_in')) {
            $CI->session->set_flashdata('error', 'Silakan login terlebih dahulu untuk mengakses sistem.');
            redirect('login');
        }
    }
}

if (!function_exists('check_admin')) {
    /**
     * Memastikan user yang login adalah ADMIN
     */
    function check_admin() {
        check_login();
        $CI =& get_instance();
        if ($CI->session->userdata('role') !== 'admin') {
            $CI->session->set_flashdata('error', 'Anda tidak memiliki akses ke halaman administrator.');
            redirect('user/dashboard');
        }
    }
}

if (!function_exists('check_user')) {
    /**
     * Memastikan user yang login adalah USER / SISWA
     */
    function check_user() {
        check_login();
        $CI =& get_instance();
        if ($CI->session->userdata('role') !== 'user') {
            redirect('admin/dashboard');
        }
    }
}

if (!function_exists('get_user_initials')) {
    /**
     * Mendapatkan inisial 2 huruf dari nama user untuk avatar
     */
    function get_user_initials($name) {
        $words = explode(' ', trim($name));
        $initials = '';
        if (isset($words[0])) {
            $initials .= strtoupper(substr($words[0], 0, 1));
        }
        if (isset($words[1])) {
            $initials .= strtoupper(substr($words[1], 0, 1));
        }
        return empty($initials) ? 'U' : $initials;
    }
}

if (!function_exists('format_tanggal_indo')) {
    /**
     * Format tanggal Indonesia sederhana (contoh: 02 Sep 2026)
     */
    function format_tanggal_indo($date_string) {
        if (empty($date_string) || $date_string === '0000-00-00') {
            return '—';
        }
        $bulan = [
            1 => 'Jan', 2 => 'Feb', 3 => 'Mar', 4 => 'Apr',
            5 => 'Mei', 6 => 'Jun', 7 => 'Jul', 8 => 'Agu',
            9 => 'Sep', 10 => 'Okt', 11 => 'Nov', 12 => 'Des'
        ];
        $time = strtotime($date_string);
        $d = date('d', $time);
        $m = (int) date('m', $time);
        $y = date('Y', $time);
        return $d . ' ' . (isset($bulan[$m]) ? $bulan[$m] : '') . ' ' . $y;
    }
}
💡 Catatan: Baris komentar (// atau /* */) bersifat opsional/penjelas logika. Tidak wajib diketik semua agar lebih cepat.
2

Header Master Template (header.php)

Lokasi Berkas: application/views/layouts/header.php

application/views/layouts/header.php PHP
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
?>
<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= isset($title) ? html_escape($title) : 'SIPAS Perpustakaan Digital' ?></title>
    <!-- Bootstrap 5 Offline -->
    <link rel="stylesheet" href="<?= base_url('assets/vendor/bootstrap/bootstrap.min.css') ?>">
    <!-- Bootstrap Icons Offline -->
    <link rel="stylesheet" href="<?= base_url('assets/vendor/bootstrap-icons/font/bootstrap-icons.min.css') ?>">
    <!-- Custom CSS -->
    <link rel="stylesheet" href="<?= base_url('assets/css/app.css') ?>">
</head>
<body class="bg-light">
💡 Catatan: Baris komentar (// atau /* */) bersifat opsional/penjelas logika. Tidak wajib diketik semua agar lebih cepat.
3

Bilah Navigasi Atas (navbar.php)

Lokasi Berkas: application/views/layouts/navbar.php

application/views/layouts/navbar.php PHP
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
$user_name = $this->session->userdata('nama') ? $this->session->userdata('nama') : 'Pengguna';
$user_initials = get_user_initials($user_name);
$user_role = $this->session->userdata('role');
?>
<header class="app-topbar">
    <div class="d-flex align-items-center gap-3">
        <!-- Mobile Toggle Button -->
        <button class="btn btn-light d-lg-none p-2 border-0" type="button" data-bs-toggle="offcanvas" data-bs-target="#mobileSidebar" aria-controls="mobileSidebar">
            <i class="bi bi-list fs-4"></i>
        </button>
        <span class="d-none d-sm-inline fw-semibold text-secondary">
            <?= $user_role === 'admin' ? 'Panel Administrator' : 'Portal Perpustakaan Siswa' ?>
        </span>
    </div>

    <div class="d-flex align-items-center gap-3">
        <div class="dropdown">
            <button class="btn btn-light border-0 d-flex align-items-center gap-2 px-2 py-1" type="button" id="userDropdown" data-bs-toggle="dropdown" aria-expanded="false">
                <div class="avatar-circle">
                    <?= $user_initials ?>
                </div>
                <div class="text-start d-none d-md-block" style="line-height: 1.2;">
                    <div class="fw-bold text-dark" style="font-size: 0.85rem;"><?= html_escape($user_name) ?></div>
                    <div class="text-muted" style="font-size: 0.72rem;"><?= ucfirst($user_role) ?></div>
                </div>
                <i class="bi bi-chevron-down ms-1 text-muted" style="font-size: 0.75rem;"></i>
            </button>
            <ul class="dropdown-menu dropdown-menu-end shadow-sm border mt-2" aria-labelledby="userDropdown">
                <li class="px-3 py-2 border-bottom">
                    <div class="fw-bold text-dark"><?= html_escape($user_name) ?></div>
                    <div class="small text-muted">@<?= html_escape($this->session->userdata('username')) ?></div>
                </li>
                <?php if ($user_role === 'user'): ?>
                    <li><a class="dropdown-item py-2" href="<?= site_url('user/profil') ?>"><i class="bi bi-person me-2 text-muted"></i> Profil Saya</a></li>
                    <li><a class="dropdown-item py-2" href="<?= site_url('user/peminjaman') ?>"><i class="bi bi-journal-check me-2 text-muted"></i> Buku Saya</a></li>
                    <li><hr class="dropdown-divider"></li>
                <?php endif; ?>
                <li><a class="dropdown-item py-2 text-danger" href="<?= site_url('logout') ?>"><i class="bi bi-box-arrow-right me-2"></i> Keluar</a></li>
            </ul>
        </div>
    </div>
</header>
💡 Catatan: Baris komentar (// atau /* */) bersifat opsional/penjelas logika. Tidak wajib diketik semua agar lebih cepat.
4

Sidebar Administrator (sidebar_admin.php)

Lokasi Berkas: application/views/layouts/sidebar_admin.php

application/views/layouts/sidebar_admin.php PHP
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
$current_page = $this->uri->segment(2);
$current_sub = $this->uri->segment(3);
?>
<!-- Desktop Sidebar -->
<aside class="app-sidebar d-none d-lg-flex">
    <div class="sidebar-brand">
        <div class="sidebar-brand-icon">
            <i class="bi bi-book-half"></i>
        </div>
        <div>
            <div class="sidebar-brand-text">SIPAS DIGITAL</div>
            <span class="sidebar-brand-sub">Perpustakaan Ardli Sela</span>
        </div>
    </div>

    <div class="sidebar-menu">
        <div class="sidebar-heading">Menu Utama</div>
        <ul class="nav flex-column">
            <li class="nav-item">
                <a class="nav-link <?= ($current_page === 'dashboard' || empty($current_page)) ? 'active' : '' ?>" href="<?= site_url('admin/dashboard') ?>">
                    <i class="bi bi-grid"></i>
                    <span>Dashboard</span>
                </a>
            </li>
        </ul>

        <div class="sidebar-heading mt-3">Master Data</div>
        <ul class="nav flex-column">
            <li class="nav-item">
                <a class="nav-link <?= ($current_page === 'buku') ? 'active' : '' ?>" href="<?= site_url('admin/buku') ?>">
                    <i class="bi bi-book"></i>
                    <span>Data Buku</span>
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link <?= ($current_page === 'anggota') ? 'active' : '' ?>" href="<?= site_url('admin/anggota') ?>">
                    <i class="bi bi-people"></i>
                    <span>Data Anggota</span>
                </a>
            </li>
        </ul>

        <div class="sidebar-heading mt-3">Transaksi</div>
        <ul class="nav flex-column">
            <li class="nav-item">
                <a class="nav-link <?= ($current_page === 'transaksi' && empty($this->input->get('status'))) ? 'active' : '' ?>" href="<?= site_url('admin/transaksi') ?>">
                    <i class="bi bi-arrow-left-right"></i>
                    <span>Semua Transaksi</span>
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link <?= ($current_page === 'transaksi' && $this->input->get('status') === 'dipinjam') ? 'active' : '' ?>" href="<?= site_url('admin/transaksi?status=dipinjam') ?>">
                    <i class="bi bi-clock-history"></i>
                    <span>Peminjaman Aktif</span>
                </a>
            </li>
        </ul>
    </div>

    <div class="sidebar-footer">
        <div class="user-badge-container">
            <div class="avatar-circle">
                <?= get_user_initials($this->session->userdata('nama')) ?>
            </div>
            <div class="overflow-hidden" style="line-height: 1.2;">
                <div class="fw-bold text-dark text-truncate" style="font-size: 0.85rem;"><?= html_escape($this->session->userdata('nama')) ?></div>
                <div class="text-muted" style="font-size: 0.72rem;">Administrator</div>
            </div>
        </div>
        <a href="<?= site_url('logout') ?>" class="btn btn-outline-danger btn-sm w-100 justify-content-center">
            <i class="bi bi-box-arrow-right"></i> Keluar
        </a>
    </div>
</aside>

<!-- Mobile Offcanvas Sidebar -->
<div class="offcanvas offcanvas-start" tabindex="-1" id="mobileSidebar" aria-labelledby="mobileSidebarLabel">
    <div class="offcanvas-header border-bottom">
        <div class="d-flex align-items-center gap-2">
            <div class="sidebar-brand-icon">
                <i class="bi bi-book-half"></i>
            </div>
            <div>
                <h6 class="offcanvas-title fw-bold" id="mobileSidebarLabel">SIPAS DIGITAL</h6>
                <span class="small text-muted">Panel Administrator</span>
            </div>
        </div>
        <button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
    </div>
    <div class="offcanvas-body p-0 d-flex flex-column">
        <div class="sidebar-menu flex-grow-1">
            <div class="sidebar-heading">Menu Utama</div>
            <ul class="nav flex-column">
                <li class="nav-item">
                    <a class="nav-link <?= ($current_page === 'dashboard' || empty($current_page)) ? 'active' : '' ?>" href="<?= site_url('admin/dashboard') ?>">
                        <i class="bi bi-grid"></i>
                        <span>Dashboard</span>
                    </a>
                </li>
            </ul>

            <div class="sidebar-heading mt-3">Master Data</div>
            <ul class="nav flex-column">
                <li class="nav-item">
                    <a class="nav-link <?= ($current_page === 'buku') ? 'active' : '' ?>" href="<?= site_url('admin/buku') ?>">
                        <i class="bi bi-book"></i>
                        <span>Data Buku</span>
                    </a>
                </li>
                <li class="nav-item">
                    <a class="nav-link <?= ($current_page === 'anggota') ? 'active' : '' ?>" href="<?= site_url('admin/anggota') ?>">
                        <i class="bi bi-people"></i>
                        <span>Data Anggota</span>
                    </a>
                </li>
            </ul>

            <div class="sidebar-heading mt-3">Transaksi</div>
            <ul class="nav flex-column">
                <li class="nav-item">
                    <a class="nav-link <?= ($current_page === 'transaksi' && empty($this->input->get('status'))) ? 'active' : '' ?>" href="<?= site_url('admin/transaksi') ?>">
                        <i class="bi bi-arrow-left-right"></i>
                        <span>Semua Transaksi</span>
                    </a>
                </li>
                <li class="nav-item">
                    <a class="nav-link <?= ($current_page === 'transaksi' && $this->input->get('status') === 'dipinjam') ? 'active' : '' ?>" href="<?= site_url('admin/transaksi?status=dipinjam') ?>">
                        <i class="bi bi-clock-history"></i>
                        <span>Peminjaman Aktif</span>
                    </a>
                </li>
            </ul>
        </div>
        <div class="sidebar-footer">
            <a href="<?= site_url('logout') ?>" class="btn btn-outline-danger btn-sm w-100 justify-content-center">
                <i class="bi bi-box-arrow-right"></i> Keluar
            </a>
        </div>
    </div>
</div>
💡 Catatan: Baris komentar (// atau /* */) bersifat opsional/penjelas logika. Tidak wajib diketik semua agar lebih cepat.
5

Sidebar Anggota Siswa (sidebar_user.php)

Lokasi Berkas: application/views/layouts/sidebar_user.php

application/views/layouts/sidebar_user.php PHP
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
$current_page = $this->uri->segment(2);
?>
<!-- Desktop Sidebar -->
<aside class="app-sidebar d-none d-lg-flex">
    <div class="sidebar-brand">
        <div class="sidebar-brand-icon">
            <i class="bi bi-book-half"></i>
        </div>
        <div>
            <div class="sidebar-brand-text">SIPAS DIGITAL</div>
            <span class="sidebar-brand-sub">Perpustakaan Ardli Sela</span>
        </div>
    </div>

    <div class="sidebar-menu">
        <div class="sidebar-heading">Menu Utama</div>
        <ul class="nav flex-column">
            <li class="nav-item">
                <a class="nav-link <?= ($current_page === 'dashboard' || empty($current_page)) ? 'active' : '' ?>" href="<?= site_url('user/dashboard') ?>">
                    <i class="bi bi-grid"></i>
                    <span>Dashboard</span>
                </a>
            </li>
        </ul>

        <div class="sidebar-heading mt-3">Perpustakaan</div>
        <ul class="nav flex-column">
            <li class="nav-item">
                <a class="nav-link <?= ($current_page === 'buku') ? 'active' : '' ?>" href="<?= site_url('user/buku') ?>">
                    <i class="bi bi-search"></i>
                    <span>Cari Buku</span>
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link <?= ($current_page === 'peminjaman') ? 'active' : '' ?>" href="<?= site_url('user/peminjaman') ?>">
                    <i class="bi bi-journal-check"></i>
                    <span>Buku Saya</span>
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link <?= ($current_page === 'riwayat') ? 'active' : '' ?>" href="<?= site_url('user/riwayat') ?>">
                    <i class="bi bi-clock-history"></i>
                    <span>Riwayat Peminjaman</span>
                </a>
            </li>
        </ul>

        <div class="sidebar-heading mt-3">Akun</div>
        <ul class="nav flex-column">
            <li class="nav-item">
                <a class="nav-link <?= ($current_page === 'profil') ? 'active' : '' ?>" href="<?= site_url('user/profil') ?>">
                    <i class="bi bi-person"></i>
                    <span>Profil Saya</span>
                </a>
            </li>
        </ul>
    </div>

    <div class="sidebar-footer">
        <div class="user-badge-container">
            <div class="avatar-circle">
                <?= get_user_initials($this->session->userdata('nama')) ?>
            </div>
            <div class="overflow-hidden" style="line-height: 1.2;">
                <div class="fw-bold text-dark text-truncate" style="font-size: 0.85rem;"><?= html_escape($this->session->userdata('nama')) ?></div>
                <div class="text-muted text-truncate" style="font-size: 0.72rem;"><?= html_escape($this->session->userdata('kelas')) ?></div>
            </div>
        </div>
        <a href="<?= site_url('logout') ?>" class="btn btn-outline-danger btn-sm w-100 justify-content-center">
            <i class="bi bi-box-arrow-right"></i> Keluar
        </a>
    </div>
</aside>

<!-- Mobile Offcanvas Sidebar -->
<div class="offcanvas offcanvas-start" tabindex="-1" id="mobileSidebar" aria-labelledby="mobileSidebarUserLabel">
    <div class="offcanvas-header border-bottom">
        <div class="d-flex align-items-center gap-2">
            <div class="sidebar-brand-icon">
                <i class="bi bi-book-half"></i>
            </div>
            <div>
                <h6 class="offcanvas-title fw-bold" id="mobileSidebarUserLabel">SIPAS DIGITAL</h6>
                <span class="small text-muted">Portal Siswa</span>
            </div>
        </div>
        <button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
    </div>
    <div class="offcanvas-body p-0 d-flex flex-column">
        <div class="sidebar-menu flex-grow-1">
            <div class="sidebar-heading">Menu Utama</div>
            <ul class="nav flex-column">
                <li class="nav-item">
                    <a class="nav-link <?= ($current_page === 'dashboard' || empty($current_page)) ? 'active' : '' ?>" href="<?= site_url('user/dashboard') ?>">
                        <i class="bi bi-grid"></i>
                        <span>Dashboard</span>
                    </a>
                </li>
            </ul>

            <div class="sidebar-heading mt-3">Perpustakaan</div>
            <ul class="nav flex-column">
                <li class="nav-item">
                    <a class="nav-link <?= ($current_page === 'buku') ? 'active' : '' ?>" href="<?= site_url('user/buku') ?>">
                        <i class="bi bi-search"></i>
                        <span>Cari Buku</span>
                    </a>
                </li>
                <li class="nav-item">
                    <a class="nav-link <?= ($current_page === 'peminjaman') ? 'active' : '' ?>" href="<?= site_url('user/peminjaman') ?>">
                        <i class="bi bi-journal-check"></i>
                        <span>Buku Saya</span>
                    </a>
                </li>
                <li class="nav-item">
                    <a class="nav-link <?= ($current_page === 'riwayat') ? 'active' : '' ?>" href="<?= site_url('user/riwayat') ?>">
                        <i class="bi bi-clock-history"></i>
                        <span>Riwayat Peminjaman</span>
                    </a>
                </li>
            </ul>

            <div class="sidebar-heading mt-3">Akun</div>
            <ul class="nav flex-column">
                <li class="nav-item">
                    <a class="nav-link <?= ($current_page === 'profil') ? 'active' : '' ?>" href="<?= site_url('user/profil') ?>">
                        <i class="bi bi-person"></i>
                        <span>Profil Saya</span>
                    </a>
                </li>
            </ul>
        </div>
        <div class="sidebar-footer">
            <a href="<?= site_url('logout') ?>" class="btn btn-outline-danger btn-sm w-100 justify-content-center">
                <i class="bi bi-box-arrow-right"></i> Keluar
            </a>
        </div>
    </div>
</div>
💡 Catatan: Baris komentar (// atau /* */) bersifat opsional/penjelas logika. Tidak wajib diketik semua agar lebih cepat.
6

Penampil Notifikasi Status (flash_message.php)

Lokasi Berkas: application/views/layouts/flash_message.php

application/views/layouts/flash_message.php PHP
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
?>
<?php if ($this->session->flashdata('success')): ?>
    <div class="alert alert-soft-success alert-dismissible fade show d-flex align-items-center mb-4 alert-auto-dismiss" role="alert">
        <i class="bi bi-check-circle-fill me-2 fs-5 text-success"></i>
        <div><?= $this->session->flashdata('success') ?></div>
        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
    </div>
<?php endif; ?>

<?php if ($this->session->flashdata('error')): ?>
    <div class="alert alert-soft-danger alert-dismissible fade show d-flex align-items-center mb-4" role="alert">
        <i class="bi bi-exclamation-triangle-fill me-2 fs-5 text-danger"></i>
        <div><?= $this->session->flashdata('error') ?></div>
        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
    </div>
<?php endif; ?>

<?php if (validation_errors()): ?>
    <div class="alert alert-soft-danger alert-dismissible fade show mb-4" role="alert">
        <div class="fw-bold mb-1"><i class="bi bi-exclamation-circle-fill me-2"></i> Periksa kembali isian formulir:</div>
        <div class="small ps-4"><?= validation_errors('<div class="mb-1">• ', '</div>') ?></div>
        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
    </div>
<?php endif; ?>
💡 Catatan: Baris komentar (// atau /* */) bersifat opsional/penjelas logika. Tidak wajib diketik semua agar lebih cepat.
7

Footer Master Template (footer.php)

Lokasi Berkas: application/views/layouts/footer.php

application/views/layouts/footer.php PHP
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
?>
    <!-- Bootstrap Bundle with Popper Offline -->
    <script src="<?= base_url('assets/vendor/bootstrap/bootstrap.bundle.min.js') ?>"></script>
    <!-- Custom App JS -->
    <script src="<?= base_url('assets/js/app.js') ?>"></script>
</body>
</html>
💡 Catatan: Baris komentar (// atau /* */) bersifat opsional/penjelas logika. Tidak wajib diketik semua agar lebih cepat.