# Frontend Menu System & CMS Builder

CMS ini mempunyai **3 konteks** frontend:

| Konteks | Guard | Deskripsi | Dokumentasi |
|---|---|---|---|
| **User Panel** (frontend-user) | `user` | Dashboard untuk user login | `setup.md`, `architecture.md` |
| **Public CMS Site** (landing page) | - | Static pages untuk public | `composers.md`, `navbar-dynamic-menu.md` |
| **CMS Builder** (FrontendSite) | - | Component-based dynamic website | `docs/module/frontend-site.md`, `docs/FRONTEND-COMPONENT-GUIDE.md` |

---

## CMS Builder (FrontendSite Module)

Module terbaru untuk membina website secara **dynamic tanpa coding**. Component-based architecture:

- **DB sebagai source of truth** → **storage files sebagai performance layer**
- Admin create site → pilih component → assign ke page → auto-render
- Portal Display dropdowns menggunakan `FrontendSite::where('status', true)` (bukan Ref(PORTAL))
- Component codes guna underscores (`hero_banner`) jadi variable `$hero_banner` dalam Blade
- **Entry Script** — init preprocessing (run first), set shared vars via `$_shared`
- **Page Content** — render utama page, guna component variables & `$_shared`
- **Layout** — override site layout (optional, toggle ON/OFF dengan radio button)
- **Monaco Editor** — popup modal dengan AJAX save (Ctrl+S), component panel dalam modal

### Demo Sites (via `WebSiteBackupSeeder`)

| Site | Slug | Type | Pages |
|------|------|------|-------|
| My Modern Site | `my-site` | Static landing | 3 (Home, About, Contact) |
| Module Content Site | `module-site` | Module content | 1 (Home with 8 DB components) |

### Seed Order
```bash
php artisan db:seed
```

### PortalHandler — Module Page Handling

**File:** `app/Services/PortalHandler.php`

Semua module content dipapar sebagai **component list** dalam page. Tiada dedicated URL path untuk detail item — detail dimuat melalui page component guna `request()->query('id')`.

| Method | Module | URL Pattern |
|--------|--------|-------------|
| `handle()` | Page biasa | `/{siteSlug}/{pageSlug}` |

**ContentArticle / Gallery detail pattern:**
```
URL: /{siteSlug}/{pageSlug}?id={article_code}
```
- `{pageSlug}` = page biasa dalam site
- `?id={code}` = query param untuk filter item detail dalam component

> Detail penuh: `docs/FRONTEND-COMPONENT-GUIDE.md` section 4.2

### Routing Summary
- **Default site:** pages accessible at `/{pageSlug}` (no site slug needed)
- **Other sites:** pages at `/{siteSlug}/{pageSlug}`
- **Root `/`:** default site home page
- **Query params:** `?id=` for ContentArticle / Gallery detail items

### Rujukan
- **`docs/module/frontend-site.md`** — Dokumentasi penuh CMS builder
- **`docs/FRONTEND-COMPONENT-GUIDE.md`** — Panduan komponen untuk 8 modul content
- **`docs/CMS-BUILDER-GUIDE.md`** — Section 10 untuk editor UI/UX details

---

## Editor Features (Monaco Popup Modal)

### Save Flow
```
Ctrl+S / Click Save → FormData POST → Controller ajax() check → Toast success
```
- AJAX save hanya hantar **field yang sedang diedit** (Entry Script / Page Content / Layout) — elak cross-field validation error.
- AJAX modal save **tidak update/create** `name` & `slug`; hanya update kod.
- Header: `X-Requested-With: XMLHttpRequest`
- Pattern sebiji macam Component module

### Create Mode Coordination
- Create form ada hidden field `page_id`.
- First modal Save akan create page dan return `page_id`.
- Main Save selepas tu update page yang sama — elak error *"The slug has already been taken"*.
- Main Save dalam create page sentiasa tunjuk flash **"Page created successfully!"**.

### Pre-editing Validation (Name & Slug)
- Editor trigger boxes dan butang Save dalam modal **disable** kalau Name atau Slug kosong.
- Kalau user cuba klik/drop tanpa isi Name/Slug:
  - Field Name & Slug border merah + shake animation.
  - Toast merah: *"Please fill in Name and Slug before editing code."*
- Error hilang automatik bila user mula taip.

### Entry Script Restriction
- Entry Script **dilarang** mengandungi `{!! $... !!}` syntax.
- Gunakan Page Content atau Layout untuk output component (`{!! $code !!}`).
- Entry Script hanya untuk `@php` logic / preprocessing.

### Component Panel dalam Modal
- Klik "Components" button dalam modal toolbar
- Search/filter components
- Recently Used (auto-save localStorage)
- Drag & drop ke editor
- Drag ghost preview (hijau)

### Editor Triggers
- Click → buka modal editor (jika Name & Slug dah diisi)
- Drag component dari drawer → drop pada trigger → auto-buka modal + insert
- Trigger show preview (first 800 chars) lepas save

---

## Struktur Direktori (Menu)

```
resources/views/backend/module/menu/
├── frontend/              ← Admin urus menu untuk frontend
│   ├── index.blade.php
│   ├── create.blade.php
│   ├── edit.blade.php
│   ├── assign.blade.php
│   └── _tree_node.blade.php
├── frontendMenuCategory/  ← Admin urus kategori menu
│   ├── index.blade.php
│   ├── create.blade.php
│   ├── edit.blade.php
│   └── form.blade.php
└── backend/               ← Admin urus menu untuk backend admin panel

resources/views/frontend/       ← CMS builder wrapper (cms.blade.php)
```

---

## Model & Table (Menu)

| Model | Table | Purpose |
|---|---|---|
| `Menu` (frontend) | `frontend_menu` | Senarai menu items |
| `MenuCategory` | `frontend_menu_category` | Kategori/label menu |
| `RoleMapping` (frontend) | `frontend_role_mapping` | Assignment menu → role |

### Table: `frontend_role_mapping`

| Field | Type | Default | Description |
|---|---|---|---|
| `role_code` | string | - | Nama role (Spatie) |
| `category_id` | FK | null | Foreign key ke `frontend_menu_category` |
| `menu_group` | string | - | Sub-kumpulan dalam category |
| `menu_id` | FK | - | Foreign key ke `frontend_menu` |
| `parent_id` | integer | 0 | Parent menu untuk hierarchy |
| `sort` | integer | - | Urutan paparan |
| `page_id` | integer | 0 | Filter by page (0 = semua page) |
| `site_id` | integer | 0 | Filter by site (0 = semua site) |
| `status` | boolean | 1 | Aktif/tidak |
