Your IP : 216.73.216.79


Current Path : /var/www/html/mysis/doc/
Upload File :
Current File : /var/www/html/mysis/doc/pagination.md

# Panduan Pagination dalam MySIS

Dokumentasi ini menerangkan cara pagination berfungsi dalam sistem MySIS, perbezaan antara pagination default Laravel dan custom partial, serta cara menggunakannya.

## 1. Dua Jenis Pagination

### A. Default Laravel Pagination

Cara guna di view:
```blade
{{ $paginator->links() }}
```

Ciri-ciri:
- Layout disediakan oleh Laravel (Tailwind view)
- Mempunyai `onEachSide(n)` untuk kawal bilangan nombor page
- Kekurangan: untuk page count yang kecil, nombor page akan bertindih (semua keluar tanpa ellipsis)

### B. Custom Partial Pagination (digunakan sekarang)

Cara guna di view:
```blade
@include('partials.pagination', ['paginator' => $paginator])
```

File: `resources/views/partials/pagination.blade.php`

Ciri-ciri:
- Layout ditulis sendiri (Prev, nombor page, Next)
- **Sentiasa konsisten** — format tetap walaupun klik prev/next
- **Current page sentiasa nampak** (highlight indigo)
- Guna `...` (ellipsis) untuk page yang jauh
- Tidak bergantung pada `onEachSide` — logik hardcode dalam partial

## 2. Perbezaan Utama

| Aspek | Default Laravel (`links()`) | Custom Partial |
|-------|----------------------------|----------------|
| Kod | `{{ $paginator->links() }}` | `@include('partials.pagination', ...)` |
| `onEachSide(n)` | ✅ Berfungsi | ❌ Diabaikan |
| Ellipsis pada page sedikit | ❌ Semua nombor keluar | ✅ Sentiasa compact |
| Info "Showing X to Y of Z" | ✅ Ada | ✅ Ada |
| Format konsisten | ❌ Nombor berubah ikut window | ✅ Tetap (1 kiri, last kanan, current tengah) |
| Kawalan penuh | Terhad | Penuh (boleh ubah style) |

## 3. onEachSide(n)

`onEachSide(n)` **hanya berfungsi dengan default Laravel pagination**.

Ia menentukan berapa nombor page yang ditunjukkan di sebelah kiri dan kanan current page.

Contoh (page 10 dari 20):
| onEachSide | Paparan |
|------------|---------|
| `1` | `1 2 ... 9 [10] 11 ... 19 20` |
| `2` | `1 2 3 ... 8 9 [10] 11 12 ... 18 19 20` |
| `3` | `1 2 3 4 ... 7 8 9 [10] 11 12 13 ... 17 18 19 20` |

**Nota:** Untuk page count yang kecil (contoh 7 pages), Laravel default akan paparkan semua nombor tanpa ellipsis kerana window first + slider + last bertindih. Ini sebab custom partial dicipta.

## 4. Format Custom Partial

Struktur asas (sentiasa sama):
```
Prev | Page 1 | ... | [Current] | ... | Last Page | Next
```

Contoh paparan untuk 7 pages:
| Page | Paparan |
|------|---------|
| Page 1 | `« Prev [1] ... 7 Next »` |
| Page 2 | `« Prev 1 [2] ... 7 Next »` |
| Page 4 | `« Prev 1 ... [4] ... 7 Next »` |
| Page 7 | `« Prev 1 ... [7] Next »` |

- Page 1 sentiasa di kiri
- Page terakhir sentiasa di kanan
- Current page (indigo) sentiasa nampak di tengah
- Ellipsis `...` untuk gap

## 5. Contoh Kod

### A. Controller (dengan paginate)

```php
// app/Http/Controllers/UserController.php

public function index(Request $request)
{
    $user = User::where('email','<>','admin@sis.com')
        ->when($request->search, function ($query, $search) {
            return $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                  ->orWhere('email', 'like', "%{$search}%");
            });
        })
        ->paginate(10)              // 10 records per page
        ->appends(['search' => $request->search]);  // kekal search semasa tukar page

    // Set bouncerRole untuk setiap user
    foreach($user as $u){
        $roleName = $u->getRoles()->first();
        if ($roleName == null) {
            $u->bouncerRole = 'No roles assigned';
        } else {
            $role = Bouncer::role()->where('name', $roleName)->first();
            $u->bouncerRole = $role->title ?? $roleName;
        }
    }

    return view('user.index')->with('user', $user);
}
```

```php
// app/Http/Controllers/SafeguardController.php

public function index(Request $request)
{
    $safeguard = Safeguard::when($request->search, function ($query, $search) {
        return $query->where(function ($q) use ($search) {
            $q->where('title', 'like', "%{$search}%")
              ->orWhere('principle', 'like', "%{$search}%");
        });
    })
    ->paginate(10)
    ->appends(['search' => $request->search]);

    return view('safeguard.index')->with('safeguard', $safeguard);
}
```

### B. View — Cara Default Laravel

```blade
{{-- resources/views/user/index.blade.php --}}
{{ $user->links() }}
```

### C. View — Cara Custom Partial (sekarang)

```blade
{{-- resources/views/user/index.blade.php --}}
@include('partials.pagination', ['paginator' => $user])
```

### D. Kod Penuh Custom Partial

File: `resources/views/partials/pagination.blade.php`

```blade
@if($paginator->hasPages())
<div class="mt-4 flex items-center justify-between">
    <div class="text-sm text-gray-500">
        Showing <span class="font-medium">{{ $paginator->firstItem() }}</span> to <span class="font-medium">{{ $paginator->lastItem() }}</span> of <span class="font-medium">{{ $paginator->total() }}</span>
    </div>
    <nav class="flex items-center gap-1">
        {{-- Prev --}}
        @if($paginator->onFirstPage())
            <span class="px-3 py-1.5 text-sm text-gray-400 bg-white border border-gray-200 rounded-md cursor-not-allowed">Prev</span>
        @else
            <a href="{{ $paginator->previousPageUrl() }}" class="px-3 py-1.5 text-sm text-gray-600 bg-white border border-gray-300 rounded-md hover:bg-gray-50">Prev</a>
        @endif

        {{-- Page 1 (sentiasa di kiri) --}}
        @if($paginator->currentPage() == 1)
            <span class="px-3 py-1.5 text-sm font-medium text-white bg-indigo-600 rounded-md">1</span>
        @else
            <a href="{{ $paginator->url(1) }}" class="px-3 py-1.5 text-sm text-gray-600 bg-white border border-gray-300 rounded-md hover:bg-gray-50">1</a>
        @endif

        {{-- Ellipsis sebelum current (jika gap) --}}
        @if($paginator->currentPage() > 3)
            <span class="px-1.5 text-sm text-gray-400">...</span>
        @endif

        {{-- Current page (di tengah) --}}
        @if($paginator->currentPage() > 1 && $paginator->currentPage() < $paginator->lastPage())
            <span class="px-3 py-1.5 text-sm font-medium text-white bg-indigo-600 rounded-md">{{ $paginator->currentPage() }}</span>
        @endif

        {{-- Ellipsis selepas current (jika gap) --}}
        @if($paginator->currentPage() < $paginator->lastPage() - 2)
            <span class="px-1.5 text-sm text-gray-400">...</span>
        @endif

        {{-- Last page (sentiasa di kanan) --}}
        @if($paginator->lastPage() > 1)
            @if($paginator->currentPage() == $paginator->lastPage())
                <span class="px-3 py-1.5 text-sm font-medium text-white bg-indigo-600 rounded-md">{{ $paginator->lastPage() }}</span>
            @else
                <a href="{{ $paginator->url($paginator->lastPage()) }}" class="px-3 py-1.5 text-sm text-gray-600 bg-white border border-gray-300 rounded-md hover:bg-gray-50">{{ $paginator->lastPage() }}</a>
            @endif
        @endif

        {{-- Next --}}
        @if($paginator->hasMorePages())
            <a href="{{ $paginator->nextPageUrl() }}" class="px-3 py-1.5 text-sm text-gray-600 bg-white border border-gray-300 rounded-md hover:bg-gray-50">Next</a>
        @else
            <span class="px-3 py-1.5 text-sm text-gray-400 bg-white border border-gray-200 rounded-md cursor-not-allowed">Next</span>
        @endif
    </nav>
</div>
@endif
```

## 6. Penjelasan Logik

### Kenapa format sentiasa konsisten?

Sebab struktur tetap: **1 sentiasa kiri, last sentiasa kanan, current sentiasa di tengah**. Yang berubah cuma angka current dan ellipsis ikut kedudukan page. Jadi tak kira page mana kau berada, layout sama je.

### Logik setiap bahagian

**1. Button Prev**
```blade
@if($paginator->onFirstPage())
    <span>Prev</span>  {{-- halaman pertama → tak boleh klik --}}
@else
    <a href="...">Prev</a>  {{-- bukan halaman pertama → boleh klik --}}
@endif
```

**2. Page 1 (sentiasa di kiri)**
```blade
@if($paginator->currentPage() == 1)
    <span class="bg-indigo-600">1</span>  {{-- current → highlight --}}
@else
    <a href="{{ $paginator->url(1) }}">1</a>  {{-- bukan current → link --}}
@endif
```

**3. Ellipsis sebelum current (kalau ada gap)**
```blade
@if($paginator->currentPage() > 3)
    <span>...</span>  {{-- jarak lebih dari 3 → tunjuk ... --}}
@endif
```
Contoh: current page 5 → ada gap dari page 1 → `1 ... 5`

**4. Current page (di tengah)**
```blade
@if($paginator->currentPage() > 1 && $paginator->currentPage() < $paginator->lastPage())
    <span class="bg-indigo-600">{{ $paginator->currentPage() }}</span>
@endif
```
Tunjuk page sekarang, warna indigo. Tak dikira bila page 1 atau page terakhir (sebab dah di-highlight kat tepi).

**5. Ellipsis selepas current**
```blade
@if($paginator->currentPage() < $paginator->lastPage() - 2)
    <span>...</span>
@endif
```

**6. Last page (sentiasa di kanan)**
```blade
@if($paginator->currentPage() == $paginator->lastPage())
    <span class="bg-indigo-600">{{ $paginator->lastPage() }}</span>
@else
    <a href="{{ $paginator->url($paginator->lastPage()) }}">{{ $paginator->lastPage() }}</a>
@endif
```

**7. Button Next** — sama macam Prev, terbalik je.

### Method Paginator yang Digunakan

| Method | Fungsi |
|--------|--------|
| `$paginator->hasPages()` | Ada lebih dari 1 page? |
| `$paginator->currentPage()` | Page sekarang |
| `$paginator->lastPage()` | Jumlah page |
| `$paginator->onFirstPage()` | Betul-betul page 1? |
| `$paginator->hasMorePages()` | Ada page seterusnya? |
| `$paginator->url($n)` | URL untuk page n |
| `$paginator->previousPageUrl()` | URL page sebelum |
| `$paginator->nextPageUrl()` | URL page selepas |
| `$paginator->firstItem()` / `lastItem()` / `total()` | Info "Showing X to Y of Z" |

## 7. Pages yang Menggunakan Custom Partial

Semua index pages berikut sudah menggunakan custom partial:

| Page | Controller Method | Variable |
|------|-------------------|----------|
| `/indicator/index` | `IndicatorController@index` | `$indicator` |
| `/safeguard/index` | `SafeguardController@index` | `$safeguard` |
| `/state/index` | `StateController@index` | `$state` |
| `/state/fmu_listing/{state}` | `StateController@fmu_listing` | `$fmus` |
| `/user/index` | `UserController@index` | `$user` |
| `/user/role_index` | `UserController@role_index` | `$role` |

## 8. Cleanup

`->onEachSide(1)` dalam controller telah **dibuang** kerana custom partial mengabaikannya (dead code).

Contoh kod bersih:
```php
->paginate(10)->appends(['search' => $request->search])
```