First commit

This commit is contained in:
Saufi
2026-05-18 08:56:23 +08:00
commit fd3d3a4d2b
147 changed files with 22099 additions and 0 deletions

View File

@@ -0,0 +1,142 @@
@extends('layouts.admin')
@section('title', 'Tambah Knowledge Item')
@section('breadcrumb')
<li class="breadcrumb-item"><a href="{{ route('admin.knowledge-items.index') }}">FAQ & Pengetahuan</a></li>
<li class="breadcrumb-item active">Tambah</li>
@endsection
@section('content')
<div class="row justify-content-center">
<div class="col-lg-9">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white border-bottom">
<h5 class="mb-0 fw-bold"><i class="bi bi-plus-circle me-2"></i>Tambah Knowledge Item</h5>
</div>
<div class="card-body p-4">
<form method="POST" action="{{ route('admin.knowledge-items.store') }}">
@csrf
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-semibold">Kategori <span class="text-danger">*</span></label>
<select name="category_id" class="form-select @error('category_id') is-invalid @enderror" required>
<option value=""> Pilih Kategori </option>
@foreach($categories as $cat)
<option value="{{ $cat->id }}"
{{ (old('category_id', $prefillData['category_id'] ?? '') == $cat->id) ? 'selected' : '' }}>
{{ $cat->name }}
</option>
@endforeach
</select>
@error('category_id')<div class="invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Jenis Item <span class="text-danger">*</span></label>
<select name="item_type" class="form-select @error('item_type') is-invalid @enderror" required>
<option value=""> Pilih Jenis </option>
@foreach($typeLabels as $value => $label)
<option value="{{ $value }}"
{{ (old('item_type', $prefillData['item_type'] ?? '') == $value) ? 'selected' : '' }}>
{{ $label }}
</option>
@endforeach
</select>
@error('item_type')<div class="invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-12">
<label class="form-label fw-semibold">
<span id="titleLabel">Tajuk</span> <span class="text-danger">*</span>
<small class="text-muted fw-normal ms-1">(untuk FAQ: tuliskan soalannya)</small>
</label>
<input type="text" name="title" class="form-control @error('title') is-invalid @enderror"
value="{{ old('title', $prefillData['title'] ?? '') }}"
placeholder="Contoh: Apakah syarat untuk memohon lesen perniagaan?" required>
@error('title')<div class="invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-12">
<label class="form-label fw-semibold">
<span id="contentLabel">Kandungan / Jawapan</span> <span class="text-danger">*</span>
</label>
<textarea name="content" class="form-control @error('content') is-invalid @enderror"
rows="8" required
placeholder="Tulis jawapan atau kandungan penuh di sini...">{{ old('content', $prefillData['content'] ?? '') }}</textarea>
<div class="d-flex justify-content-between">
@error('content')<div class="invalid-feedback">{{ $message }}</div>@enderror
<small class="text-muted ms-auto mt-1" id="charCount">0 / 10,000</small>
</div>
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Bahasa</label>
<select name="language" class="form-select">
<option value="ms" {{ old('language', 'ms') == 'ms' ? 'selected' : '' }}>Bahasa Melayu</option>
<option value="en" {{ old('language') == 'en' ? 'selected' : '' }}>English</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Tarikh Kuat Kuasa</label>
<input type="date" name="effective_date" class="form-control"
value="{{ old('effective_date') }}">
</div>
<div class="col-md-6">
<div class="form-check form-switch mt-2">
<input type="hidden" name="is_active" value="0">
<input class="form-check-input" type="checkbox" name="is_active" value="1"
id="isActive" {{ old('is_active', '1') ? 'checked' : '' }}>
<label class="form-check-label" for="isActive">Aktifkan selepas simpan</label>
</div>
</div>
<div class="col-md-6">
<div class="form-check form-switch mt-2">
<input type="hidden" name="is_public" value="0">
<input class="form-check-input" type="checkbox" name="is_public" value="1"
id="isPublic" {{ old('is_public', '1') ? 'checked' : '' }}>
<label class="form-check-label" for="isPublic">Boleh dicari oleh public</label>
</div>
</div>
</div>
<div class="d-flex gap-2 mt-4 pt-3 border-top">
<button type="submit" class="btn btn-primary">
<i class="bi bi-save me-1"></i>Simpan & Embed
</button>
<a href="{{ route('admin.knowledge-items.index') }}" class="btn btn-outline-secondary">Batal</a>
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
// Kira karakter
$('textarea[name="content"]').on('input', function() {
const count = $(this).val().length;
$('#charCount').text(count.toLocaleString() + ' / 10,000');
if (count > 9000) $('#charCount').addClass('text-warning');
else $('#charCount').removeClass('text-warning');
});
$('textarea[name="content"]').trigger('input');
// Update label ikut jenis
$('select[name="item_type"]').on('change', function() {
if ($(this).val() === 'faq') {
$('#titleLabel').text('Soalan');
$('#contentLabel').text('Jawapan');
} else {
$('#titleLabel').text('Tajuk');
$('#contentLabel').text('Kandungan');
}
});
$('select[name="item_type"]').trigger('change');
</script>
@endpush

View File

@@ -0,0 +1,107 @@
@extends('layouts.admin')
@section('title', 'Edit Knowledge Item')
@section('breadcrumb')
<li class="breadcrumb-item"><a href="{{ route('admin.knowledge-items.index') }}">FAQ & Pengetahuan</a></li>
<li class="breadcrumb-item"><a href="{{ route('admin.knowledge-items.show', $knowledgeItem) }}">{{ Str::limit($knowledgeItem->title, 30) }}</a></li>
<li class="breadcrumb-item active">Edit</li>
@endsection
@section('content')
<div class="row justify-content-center">
<div class="col-lg-9">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white border-bottom">
<h5 class="mb-0 fw-bold"><i class="bi bi-pencil me-2"></i>Edit Knowledge Item</h5>
</div>
<div class="card-body p-4">
<form method="POST" action="{{ route('admin.knowledge-items.update', $knowledgeItem) }}">
@csrf @method('PUT')
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-semibold">Kategori <span class="text-danger">*</span></label>
<select name="category_id" class="form-select @error('category_id') is-invalid @enderror" required>
<option value=""> Pilih Kategori </option>
@foreach($categories as $cat)
<option value="{{ $cat->id }}"
{{ old('category_id', $knowledgeItem->category_id) == $cat->id ? 'selected' : '' }}>
{{ $cat->name }}
</option>
@endforeach
</select>
@error('category_id')<div class="invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Jenis Item <span class="text-danger">*</span></label>
<select name="item_type" class="form-select @error('item_type') is-invalid @enderror" required>
@foreach($typeLabels as $value => $label)
<option value="{{ $value }}"
{{ old('item_type', $knowledgeItem->item_type) == $value ? 'selected' : '' }}>
{{ $label }}
</option>
@endforeach
</select>
@error('item_type')<div class="invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-12">
<label class="form-label fw-semibold">Tajuk / Soalan <span class="text-danger">*</span></label>
<input type="text" name="title" class="form-control @error('title') is-invalid @enderror"
value="{{ old('title', $knowledgeItem->title) }}" required>
@error('title')<div class="invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-12">
<label class="form-label fw-semibold">Kandungan / Jawapan <span class="text-danger">*</span></label>
<textarea name="content" class="form-control @error('content') is-invalid @enderror"
rows="10" required>{{ old('content', $knowledgeItem->content) }}</textarea>
@error('content')<div class="invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Bahasa</label>
<select name="language" class="form-select">
<option value="ms" {{ old('language', $knowledgeItem->language) == 'ms' ? 'selected' : '' }}>BM</option>
<option value="en" {{ old('language', $knowledgeItem->language) == 'en' ? 'selected' : '' }}>EN</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Tarikh Kuat Kuasa</label>
<input type="date" name="effective_date" class="form-control"
value="{{ old('effective_date', $knowledgeItem->effective_date?->toDateString()) }}">
</div>
<div class="col-md-6">
<div class="form-check form-switch mt-2">
<input type="hidden" name="is_active" value="0">
<input class="form-check-input" type="checkbox" name="is_active" value="1"
id="isActive" {{ old('is_active', $knowledgeItem->is_active) ? 'checked' : '' }}>
<label class="form-check-label" for="isActive">Aktif</label>
</div>
</div>
<div class="col-md-6">
<div class="form-check form-switch mt-2">
<input type="hidden" name="is_public" value="0">
<input class="form-check-input" type="checkbox" name="is_public" value="1"
id="isPublic" {{ old('is_public', $knowledgeItem->is_public) ? 'checked' : '' }}>
<label class="form-check-label" for="isPublic">Awam</label>
</div>
</div>
</div>
<div class="d-flex gap-2 mt-4 pt-3 border-top">
<button type="submit" class="btn btn-primary">
<i class="bi bi-save me-1"></i>Kemaskini & Re-embed
</button>
<a href="{{ route('admin.knowledge-items.show', $knowledgeItem) }}" class="btn btn-outline-secondary">Batal</a>
</div>
</form>
</div>
</div>
</div>
</div>
@endsection

View File

@@ -0,0 +1,142 @@
@extends('layouts.admin')
@section('title', 'FAQ & Pengetahuan')
@section('breadcrumb')
<li class="breadcrumb-item active">FAQ & Pengetahuan</li>
@endsection
@section('content')
<div class="d-flex align-items-center justify-content-between mb-4">
<h4 class="mb-0 fw-bold">FAQ & Pengetahuan</h4>
<a href="{{ route('admin.knowledge-items.create') }}" class="btn btn-primary">
<i class="bi bi-plus-circle me-1"></i>Tambah Item
</a>
</div>
{{-- Filter --}}
<div class="card border-0 shadow-sm mb-4">
<div class="card-body py-3">
<form method="GET" class="row g-2 align-items-end">
<div class="col-md-4">
<input type="text" name="search" class="form-control form-control-sm"
placeholder="Cari tajuk atau kandungan..." value="{{ request('search') }}">
</div>
<div class="col-md-3">
<select name="category_id" class="form-select form-select-sm">
<option value="">Semua Kategori</option>
@foreach($categories as $cat)
<option value="{{ $cat->id }}" {{ request('category_id') == $cat->id ? 'selected' : '' }}>
{{ $cat->name }}
</option>
@endforeach
</select>
</div>
<div class="col-md-2">
<select name="item_type" class="form-select form-select-sm">
<option value="">Semua Jenis</option>
@foreach($typeLabels as $value => $label)
<option value="{{ $value }}" {{ request('item_type') == $value ? 'selected' : '' }}>
{{ $label }}
</option>
@endforeach
</select>
</div>
<div class="col-auto">
<button type="submit" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-search me-1"></i>Tapis
</button>
</div>
</form>
</div>
</div>
{{-- Table --}}
<div class="card border-0 shadow-sm">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="table-light">
<tr>
<th class="ps-3">Tajuk / Soalan</th>
<th>Kategori</th>
<th>Jenis</th>
<th>Status</th>
<th>Embed</th>
<th class="text-end pe-3">Tindakan</th>
</tr>
</thead>
<tbody>
@forelse($items as $item)
<tr class="{{ $item->trashed() ? 'opacity-50' : '' }}">
<td class="ps-3">
<div class="fw-semibold">{{ Str::limit($item->title, 80) }}</div>
<small class="text-muted">{{ Str::limit(strip_tags($item->content), 80) }}</small>
</td>
<td>
<span class="badge" style="background:{{ $item->category->color ?? '#6c757d' }}">
{{ $item->category->name }}
</span>
</td>
<td>
@php
$typeColors = ['faq' => 'bg-primary', 'policy' => 'bg-success', 'note' => 'bg-warning', 'announcement' => 'bg-info'];
@endphp
<span class="badge {{ $typeColors[$item->item_type] ?? 'bg-secondary' }}">
{{ $typeLabels[$item->item_type] ?? $item->item_type }}
</span>
</td>
<td>
@if($item->trashed())
<span class="badge bg-danger">Dipadam</span>
@elseif($item->is_active)
<span class="badge bg-success">Aktif</span>
@else
<span class="badge bg-secondary">Tidak Aktif</span>
@endif
</td>
<td>
@if($item->is_embedded)
<i class="bi bi-check-circle-fill text-success" title="Sudah di-embed"></i>
@else
<i class="bi bi-clock text-warning" title="Belum di-embed"></i>
@endif
</td>
<td class="text-end pe-3">
@unless($item->trashed())
<a href="{{ route('admin.knowledge-items.show', $item) }}"
class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i>
</a>
<a href="{{ route('admin.knowledge-items.edit', $item) }}"
class="btn btn-sm btn-outline-secondary">
<i class="bi bi-pencil"></i>
</a>
<form method="POST" action="{{ route('admin.knowledge-items.toggle-status', $item) }}" class="d-inline">
@csrf @method('PATCH')
<button type="submit" class="btn btn-sm {{ $item->is_active ? 'btn-outline-warning' : 'btn-outline-success' }}"
title="{{ $item->is_active ? 'Nyahaktifkan' : 'Aktifkan' }}">
<i class="bi {{ $item->is_active ? 'bi-toggle-on' : 'bi-toggle-off' }}"></i>
</button>
</form>
@endunless
</td>
</tr>
@empty
<tr>
<td colspan="6" class="text-center text-muted py-5">
<i class="bi bi-lightbulb fs-2 d-block mb-2 opacity-25"></i>
Tiada knowledge item ditemui.
<a href="{{ route('admin.knowledge-items.create') }}">Tambah yang pertama.</a>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@if($items->hasPages())
<div class="card-footer bg-white border-top py-3">
{{ $items->links() }}
</div>
@endif
</div>
@endsection

View File

@@ -0,0 +1,112 @@
@extends('layouts.admin')
@section('title', 'Knowledge Item')
@section('breadcrumb')
<li class="breadcrumb-item"><a href="{{ route('admin.knowledge-items.index') }}">FAQ & Pengetahuan</a></li>
<li class="breadcrumb-item active">{{ Str::limit($knowledgeItem->title, 40) }}</li>
@endsection
@section('content')
<div class="d-flex align-items-start justify-content-between mb-4">
<div>
<div class="d-flex align-items-center gap-2 mb-1 flex-wrap">
@php $typeColors = ['faq' => 'bg-primary', 'policy' => 'bg-success', 'note' => 'bg-warning', 'announcement' => 'bg-info']; @endphp
<span class="badge {{ $typeColors[$knowledgeItem->item_type] ?? 'bg-secondary' }}">
{{ $knowledgeItem->type_label }}
</span>
<span class="badge" style="background:{{ $knowledgeItem->category->color ?? '#6c757d' }}">
{{ $knowledgeItem->category->name }}
</span>
<span class="badge {{ $knowledgeItem->is_active ? 'bg-success' : 'bg-secondary' }}">
{{ $knowledgeItem->is_active ? 'Aktif' : 'Tidak Aktif' }}
</span>
@if($knowledgeItem->is_embedded)
<span class="badge bg-success-subtle text-success border border-success">
<i class="bi bi-check2 me-1"></i>Di-embed
</span>
@else
<span class="badge bg-warning-subtle text-warning border border-warning">
<i class="bi bi-clock me-1"></i>Belum Embed
</span>
@endif
</div>
<h4 class="mb-0 fw-bold">{{ $knowledgeItem->title }}</h4>
</div>
<div class="d-flex gap-2">
<a href="{{ route('admin.knowledge-items.edit', $knowledgeItem) }}" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-pencil me-1"></i>Edit
</a>
<form method="POST" action="{{ route('admin.knowledge-items.reindex', $knowledgeItem) }}">
@csrf
<button type="submit" class="btn btn-outline-info btn-sm">
<i class="bi bi-arrow-repeat me-1"></i>Re-embed
</button>
</form>
<form method="POST" action="{{ route('admin.knowledge-items.toggle-status', $knowledgeItem) }}">
@csrf @method('PATCH')
<button type="submit" class="btn btn-sm {{ $knowledgeItem->is_active ? 'btn-warning' : 'btn-success' }}">
{{ $knowledgeItem->is_active ? 'Nyahaktifkan' : 'Aktifkan' }}
</button>
</form>
</div>
</div>
<div class="row g-4">
<div class="col-lg-8">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white border-bottom">
<h6 class="mb-0 fw-semibold">Kandungan</h6>
</div>
<div class="card-body">
@if($knowledgeItem->item_type === 'faq')
<div class="mb-3">
<label class="text-muted small fw-semibold text-uppercase" style="font-size:.7rem">Soalan</label>
<div class="p-3 bg-light rounded mt-1 fw-semibold">{{ $knowledgeItem->title }}</div>
</div>
<div>
<label class="text-muted small fw-semibold text-uppercase" style="font-size:.7rem">Jawapan</label>
<div class="p-3 border rounded mt-1" style="white-space:pre-wrap">{{ $knowledgeItem->content }}</div>
</div>
@else
<div style="white-space:pre-wrap">{{ $knowledgeItem->content }}</div>
@endif
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white border-bottom"><h6 class="mb-0 fw-semibold">Maklumat</h6></div>
<div class="card-body small">
<dl class="row mb-0">
<dt class="col-5 text-muted">Bahasa</dt>
<dd class="col-7">{{ $knowledgeItem->language == 'ms' ? 'BM' : 'EN' }}</dd>
@if($knowledgeItem->effective_date)
<dt class="col-5 text-muted">Kuat Kuasa</dt>
<dd class="col-7">{{ $knowledgeItem->effective_date->format('d/m/Y') }}</dd>
@endif
<dt class="col-5 text-muted">Dicipta</dt>
<dd class="col-7">{{ $knowledgeItem->created_at->format('d/m/Y H:i') }}</dd>
@if($knowledgeItem->embedded_at)
<dt class="col-5 text-muted">Di-embed</dt>
<dd class="col-7">{{ $knowledgeItem->embedded_at->format('d/m/Y H:i') }}</dd>
@endif
@if($knowledgeItem->creator)
<dt class="col-5 text-muted">Dibuat oleh</dt>
<dd class="col-7">{{ $knowledgeItem->creator->name }}</dd>
@endif
<dt class="col-5 text-muted">Awam</dt>
<dd class="col-7">{{ $knowledgeItem->is_public ? 'Ya' : 'Tidak' }}</dd>
</dl>
@if($knowledgeItem->tags)
<div class="mt-2">
@foreach($knowledgeItem->tags as $tag)
<span class="badge bg-light text-dark border me-1">{{ $tag }}</span>
@endforeach
</div>
@endif
</div>
</div>
</div>
</div>
@endsection