diff --git a/app/Http/Controllers/Web/ArtikelController.php b/app/Http/Controllers/Web/ArtikelController.php
new file mode 100644
index 00000000..7f1785f1
--- /dev/null
+++ b/app/Http/Controllers/Web/ArtikelController.php
@@ -0,0 +1,77 @@
+artikelService = $artikelService;
+ }
+
+ /**
+ * Tampilkan daftar artikel OpenSID.
+ *
+ * @param Request $request
+ * @return \Illuminate\View\View
+ */
+ public function index(Request $request)
+ {
+ $search = $request->get('search', '');
+ $categoryId = $request->get('kategori', '');
+
+ $filters = [];
+ if (!empty($search)) {
+ $filters['filter[search]'] = $search;
+ }
+ if (!empty($categoryId)) {
+ $filters['filter[id_kategori]'] = $categoryId;
+ }
+
+ // Ambil data melalui service
+ // Format Pagination API json format
+ $filters['page[number]'] = $request->get('page', 1);
+ $filters['page[size]'] = 6;
+ $filters['sort'] = '-tgl_upload'; // Terurut berdasarkan tanggal terbaru
+
+ // Caching ditangani oleh ArtikelService
+ $articles = $this->artikelService->artikel($filters);
+
+ // Filter out disabled articles just in case API returns them
+ $articles = $articles->filter(function ($item) {
+ return isset($item->enabled) && $item->enabled == 1;
+ });
+
+ return view('web.artikel.index', [
+ 'title' => 'Artikel Berita',
+ 'articles' => $articles,
+ 'search' => $search,
+ 'categoryId' => $categoryId
+ ]);
+ }
+
+ /**
+ * Tampilkan detail artikel OpenSID.
+ *
+ * @param int $id
+ * @return \Illuminate\View\View
+ */
+ public function show($id)
+ {
+ $article = $this->artikelService->artikelById($id);
+
+ if (!$article || !isset($article->enabled) || $article->enabled == 0) {
+ abort(404, 'Artikel tidak ditemukan atau tidak aktif');
+ }
+
+ return view('web.artikel.show', [
+ 'object' => $article
+ ]);
+ }
+}
diff --git a/app/Services/ArtikelService.php b/app/Services/ArtikelService.php
index 5b899677..618ea0c0 100644
--- a/app/Services/ArtikelService.php
+++ b/app/Services/ArtikelService.php
@@ -14,12 +14,26 @@ public function artikel(array $filters = [])
// Ambil dari cache dulu
return Cache::remember($cacheKey, $this->cacheTtl, function () use ($filters) {
- $data = $this->apiRequest('/api/v1/artikel', $filters);
- if (! $data) {
+ $data = $this->apiRequest('/api/v1/artikel/list', $filters);
+ if (!$data) {
return collect([]);
}
-
- return collect($data)->map(fn ($item) => (object) $item['attributes']);
+ return collect($data)->map(function ($item) {
+ // Return 'attributes' but with 'id' populated
+ $attributes = $item['attributes'] ?? [];
+ $attributes['id'] = $item['id'] ?? null;
+
+ // Fetch detail to enrich with gambar and isi if missing
+ if (isset($attributes['id']) && (!isset($attributes['gambar']) || !isset($attributes['isi']))) {
+ $detail = $this->artikelById($attributes['id']);
+ if ($detail) {
+ $attributes['gambar'] = $detail->gambar ?? null;
+ $attributes['isi'] = $detail->isi ?? null;
+ }
+ }
+
+ return (object) $attributes;
+ });
});
}
@@ -32,8 +46,8 @@ public function artikelById(int $id)
'id' => $id,
]);
- if (is_array($data) && isset($data['data'])) {
- return (object) $data['data'];
+ if (is_array($data) && count($data) > 0) {
+ return (object) $data;
}
return null;
diff --git a/resources/views/web/artikel/index.blade.php b/resources/views/web/artikel/index.blade.php
new file mode 100644
index 00000000..7593e8bc
--- /dev/null
+++ b/resources/views/web/artikel/index.blade.php
@@ -0,0 +1,89 @@
+@extends('layouts.web')
+
+@section('content')
+
+
+
+
+
+
+
+
+
+
+
+ @forelse ($articles as $article)
+
+
+ @if (isset($article->gambar) && !empty($article->gambar))
+
+ @else
+
+ Placeholder
+ Thumbnail
+
+ @endif
+
+
{{ $article->judul ?? '' }}
+
+ {{ $article->kategori_nama ?? 'Kategori' }}
+
+
+ {!! Str::words(strip_tags($article->isi ?? ''), 20, '...') !!}
+
+
+
+
+ {{ isset($article->tgl_upload) ? \Carbon\Carbon::parse($article->tgl_upload)->translatedFormat('d F Y') : '' }}
+
+
+
+
+
+ @empty
+
+
+ Belum ada artikel yang dipublikasikan.
+
+
+ @endforelse
+
+
+
+
+
+
+@endsection
\ No newline at end of file
diff --git a/resources/views/web/artikel/show.blade.php b/resources/views/web/artikel/show.blade.php
new file mode 100644
index 00000000..cccd82a4
--- /dev/null
+++ b/resources/views/web/artikel/show.blade.php
@@ -0,0 +1,74 @@
+@extends('layouts.web')
+
+@section('content')
+
+
+
+
+
+
+
+
+
+
+
+
+ @if (isset($object->gambar) && !empty($object->gambar))
+
+ @endif
+
+
+
+ {!! $object->isi ?? '' !!}
+
+
+
+
+
+
+
+
+
+
+@endsection
+
+@push('styles')
+
+@endpush
\ No newline at end of file
diff --git a/resources/views/web/index.blade.php b/resources/views/web/index.blade.php
index 5a807326..2c887c43 100644
--- a/resources/views/web/index.blade.php
+++ b/resources/views/web/index.blade.php
@@ -32,6 +32,12 @@
+
+
+ @include('web.partials.artikel_terbaru')
+
+
+
@include('web.partials.team')
@@ -41,7 +47,7 @@
@push('scripts')
-@endpush
+@endpush
\ No newline at end of file
diff --git a/resources/views/web/partials/artikel_terbaru.blade.php b/resources/views/web/partials/artikel_terbaru.blade.php
new file mode 100644
index 00000000..685ec992
--- /dev/null
+++ b/resources/views/web/partials/artikel_terbaru.blade.php
@@ -0,0 +1,124 @@
+
+
+
+
+
Artikel Terbaru
+
Berita dan informasi terbaru seputar {{ config('app.sebutanKab') }}
+
+
+
+
+
+
+
+
+ @for ($i = 0; $i < 6; $i++)
+
+ @endfor
+
+
+
+
+
+@push('scripts')
+
+@endpush
\ No newline at end of file
diff --git a/routes/web.php b/routes/web.php
index 013484a9..5e5fb95c 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -399,8 +399,12 @@
Route::get('/geo-spasial', [PresisiController::class, 'geoSpasial'])->name('presisi.geo-spasial');
});
+use App\Http\Controllers\Web\ArtikelController;
+
Route::middleware(['website.enable', 'log.visitor'])->group(function () {
Route::get('/', [PageController::class, 'getIndex'])->name('web.index');
+ Route::get('artikel-opensid', [ArtikelController::class, 'index'])->name('web.artikel.index');
+ Route::get('artikel-opensid/{id}', [ArtikelController::class, 'show'])->name('web.artikel.show');
Route::get('a/{aSlug}', [PageController::class, 'getArticle'])->name('article');
Route::get('p/{pSlug}', [PageController::class, 'getPage'])->name('page');
Route::get('c/{cSlug}', [PageController::class, 'getCategory'])->name('category');
diff --git a/tests/Feature/ArtikelWebTest.php b/tests/Feature/ArtikelWebTest.php
new file mode 100644
index 00000000..4eb7e255
--- /dev/null
+++ b/tests/Feature/ArtikelWebTest.php
@@ -0,0 +1,98 @@
+withoutMiddleware([\App\Http\Middleware\WebsiteEnable::class]);
+
+ // Mock the ArtikelService
+ $mockService = Mockery::mock(ArtikelService::class);
+ $mockService->shouldReceive('artikel')->andReturn(collect([
+ (object) [
+ 'id' => 1,
+ 'judul' => 'Test Artikel OpenSID',
+ 'isi' => 'Konten artikel test',
+ 'id_kategori' => 1,
+ 'kategori_nama' => 'Berita Desa',
+ 'tgl_upload' => '2023-10-01 10:00:00',
+ 'enabled' => 1,
+ ]
+ ]));
+
+ $this->app->instance(ArtikelService::class, $mockService);
+
+ $response = $this->get(route('web.artikel.index'));
+ $response->dump();
+ $response->assertStatus(200);
+ $response->assertViewIs('web.artikel.index');
+ $response->assertSee('Artikel Berita');
+ $response->assertSee('Test Artikel OpenSID');
+ $response->assertSee('Berita Desa');
+ }
+
+ /** @test */
+ public function it_can_access_public_artikel_show()
+ {
+ $this->withoutMiddleware([\App\Http\Middleware\WebsiteEnable::class]);
+
+ // Mock the ArtikelService
+ $mockService = Mockery::mock(ArtikelService::class);
+ $mockService->shouldReceive('artikelById')->with(1)->andReturn((object) [
+ 'id' => 1,
+ 'judul' => 'Detail Test Artikel',
+ 'isi' => 'Konten detail artikel test',
+ 'id_kategori' => 1,
+ 'kategori_nama' => 'Berita Desa',
+ 'tgl_upload' => '2023-10-01 10:00:00',
+ 'enabled' => 1,
+ ]);
+
+ $this->app->instance(ArtikelService::class, $mockService);
+
+ $response = $this->get(route('web.artikel.show', ['id' => 1]));
+ $response->assertStatus(200);
+ $response->assertViewIs('web.artikel.show');
+ $response->assertSee('Detail Test Artikel');
+ $response->assertSee('Konten detail artikel test');
+ }
+
+ /** @test */
+ public function it_aborts_404_for_disabled_or_missing_artikel()
+ {
+ $this->withoutMiddleware([\App\Http\Middleware\WebsiteEnable::class]);
+
+ // Mock the ArtikelService
+ $mockService = Mockery::mock(ArtikelService::class);
+ $mockService->shouldReceive('artikelById')->with(99)->andReturn(null);
+
+ $mockService->shouldReceive('artikelById')->with(2)->andReturn((object) [
+ 'id' => 2,
+ 'judul' => 'Hidden Artikel',
+ 'enabled' => 0,
+ ]);
+
+ $this->app->instance(ArtikelService::class, $mockService);
+
+ // Test non-existent article
+ $response404 = $this->get(route('web.artikel.show', ['id' => 99]));
+ $response404->assertStatus(404);
+
+ // Test disabled article
+ $responseDisabled = $this->get(route('web.artikel.show', ['id' => 2]));
+ $responseDisabled->assertStatus(404);
+ }
+}