Skip to content

Commit e492d1e

Browse files
Implement Announcement feature: add model, resource, policy, migration, and integrate into Nova dashboard
1 parent a0b8761 commit e492d1e

File tree

13 files changed

+385
-276
lines changed

13 files changed

+385
-276
lines changed

app/Models/Announcement.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace App\Models;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
use Mostafaznv\LaraCache\CacheEntity;
7+
use Mostafaznv\LaraCache\Traits\LaraCache;
8+
9+
class Announcement extends Model
10+
{
11+
use LaraCache;
12+
13+
public static function cacheEntities(): array
14+
{
15+
return [
16+
CacheEntity::make('latest')
17+
->cache(function () {
18+
return Announcement::latest()->take(3)->get();
19+
}),
20+
];
21+
}
22+
}

app/Nova/Announcement.php

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
namespace App\Nova;
4+
5+
use App\Helpers\Helper;
6+
use Laravel\Nova\Fields\Image;
7+
use Laravel\Nova\Fields\Text;
8+
use Laravel\Nova\Fields\Textarea;
9+
use Laravel\Nova\Http\Requests\NovaRequest;
10+
11+
class Announcement extends Resource
12+
{
13+
/**
14+
* The model the resource corresponds to.
15+
*
16+
* @var class-string<\App\Models\Announcement>
17+
*/
18+
public static $model = \App\Models\Announcement::class;
19+
20+
public static function label()
21+
{
22+
return 'Pengumuman';
23+
}
24+
25+
/**
26+
* The single value that should be used to represent the resource when being displayed.
27+
*
28+
* @var string
29+
*/
30+
public static $title = 'title';
31+
32+
public function subtitle()
33+
{
34+
return Helper::terbilangTanggal($this->created_at);
35+
}
36+
37+
/**
38+
* The columns that should be searched.
39+
*
40+
* @var array
41+
*/
42+
public static $search = [
43+
'title', 'description',
44+
];
45+
46+
/**
47+
* Get the fields displayed by the resource.
48+
*
49+
* @return array
50+
*/
51+
public function fields(NovaRequest $request)
52+
{
53+
return [
54+
Text::make('Judul', 'title')
55+
->rules('required', 'max:255'),
56+
Textarea::make('Deskripsi', 'description')
57+
->rules('required')
58+
->alwaysShow(),
59+
Text::make('Link', 'link')
60+
->rules('required', 'url'),
61+
Image::make('Image')
62+
->disk('announcement')
63+
->creationRules('required')
64+
->disableDownload()
65+
->hideFromIndex()
66+
->prunable()
67+
->help('Ukuran landscape 2:1'),
68+
69+
];
70+
}
71+
72+
/**
73+
* Get the cards available for the request.
74+
*
75+
* @return array
76+
*/
77+
public function cards(NovaRequest $request)
78+
{
79+
return [];
80+
}
81+
82+
/**
83+
* Get the filters available for the resource.
84+
*
85+
* @return array
86+
*/
87+
public function filters(NovaRequest $request)
88+
{
89+
return [];
90+
}
91+
92+
/**
93+
* Get the lenses available for the resource.
94+
*
95+
* @return array
96+
*/
97+
public function lenses(NovaRequest $request)
98+
{
99+
return [];
100+
}
101+
102+
/**
103+
* Get the actions available for the resource.
104+
*
105+
* @return array
106+
*/
107+
public function actions(NovaRequest $request)
108+
{
109+
return [];
110+
}
111+
}

app/Nova/Dashboards/Main.php

Lines changed: 82 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
namespace App\Nova\Dashboards;
44

55
use App\Helpers\Helper;
6-
use App\Nova\Metrics\Kegiatan;
6+
use App\Models\Announcement;
7+
use App\Models\DaftarKegiatan;
8+
use Illuminate\Support\Facades\Storage;
79
use Laravel\Nova\Dashboards\Main as Dashboard;
10+
use Laravelwebdev\ListCard\ListCard;
11+
use Laravelwebdev\NewsCard\NewsCard;
812
use Laravelwebdev\NovaQuotes\NovaQuotes;
913
use Richardkeep\NovaTimenow\NovaTimenow;
1014

@@ -31,30 +35,83 @@ public function cards()
3135
return Helper::ROLE[$key];
3236
}, session('role'));
3337

34-
$cards = [
35-
NovaQuotes::make()
36-
->greetings(__('Welcome Back!'))
37-
->user(auth()->user()->name ?? 'Guest')
38-
->width('2/3')
39-
->description('Role: '.implode(', ', $values))
40-
->render(),
41-
NovaTimenow::make()
42-
->width('1/3')
43-
->timezones([
44-
'Asia/Pontianak',
45-
'Asia/Makassar',
46-
'Asia/Jayapura',
47-
])->defaultTimezone(config('app.timezone')),
48-
Kegiatan::make('Deadline')
49-
->emptyText('Tidak ada deadline')
50-
->width('1/3'),
51-
Kegiatan::make('Rapat')
52-
->emptyText('Tidak ada rapat')
53-
->width('1/3'),
54-
Kegiatan::make('Libur')
55-
->emptyText('Tidak ada hari libur')
56-
->width('1/3'),
57-
];
38+
$cards = [];
39+
40+
$items = DaftarKegiatan::whereIn('jenis', ['Libur', 'Deadline', 'Rapat'])
41+
->where(function ($query) {
42+
$query->where('jenis', 'Libur')
43+
->orWhere(function ($q) {
44+
$q->whereIn('jenis', ['Deadline', 'Rapat'])
45+
->whereDate('awal', '>=', now()->toDateString());
46+
});
47+
})
48+
->orderBy('awal')
49+
->get()
50+
->groupBy('jenis');
51+
52+
$kegiatan = ($items['Libur'] ?? collect())->map(function ($item) {
53+
return [
54+
'title' => Helper::terbilangHari($item->awal).', '.Helper::terbilangTanggal($item->awal),
55+
'description' => $item->kegiatan,
56+
];
57+
})->values()->toArray();
58+
59+
$deadline = ($items['Deadline'] ?? collect())->map(function ($item) {
60+
return [
61+
'title' => Helper::terbilangHari($item->awal).', '.Helper::terbilangTanggal($item->awal),
62+
'description' => $item->kegiatan,
63+
];
64+
})->values()->toArray();
65+
66+
$rapat = ($items['Rapat'] ?? collect())->map(function ($item) {
67+
return [
68+
'title' => Helper::terbilangHari($item->awal).', '.Helper::terbilangTanggal($item->awal),
69+
'description' => $item->kegiatan,
70+
];
71+
})->values()->toArray();
72+
73+
$pengumuman = Announcement::cache()->get('latest');
74+
75+
$cards[] = NovaQuotes::make()
76+
->greetings(__('Welcome Back!'))
77+
->user(auth()->user()->name ?? 'Guest')
78+
->width('2/3')
79+
->description('Role: '.implode(', ', $values))
80+
->render();
81+
82+
$cards[] = NovaTimenow::make()
83+
->width('1/3')
84+
->timezones([
85+
'Asia/Pontianak',
86+
'Asia/Makassar',
87+
'Asia/Jayapura',
88+
])->defaultTimezone(config('app.timezone'));
89+
90+
foreach ($pengumuman as $item) {
91+
$cards[] = NewsCard::make(
92+
title: $item->title,
93+
description: $item->description,
94+
image: Storage::disk('announcement')->url($item->image),
95+
link: $item->link,
96+
buttonCaption: 'Pelajari'
97+
);
98+
99+
}
100+
101+
$cards[] = ListCard::make()
102+
->title('Deadline Mendatang')
103+
->items($deadline)
104+
->emptyText('Tidak ada Deadline');
105+
106+
$cards[] = ListCard::make()
107+
->title('Rapat Mendatang')
108+
->items($rapat)
109+
->emptyText('Tidak ada Rapat');
110+
111+
$cards[] = ListCard::make()
112+
->title('Hari Libur Nasional')
113+
->items($kegiatan)
114+
->emptyText('Tidak ada hari libur nasional');
58115

59116
return $cards;
60117
}

app/Nova/Dashboards/SystemHealth.php

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
namespace App\Nova\Dashboards;
44

5-
use App\Nova\Metrics\BackupsTable;
6-
use App\Nova\Metrics\IssuesTable;
7-
use App\Nova\Metrics\OutdatedTable;
5+
use App\Helpers\Api;
86
use App\Nova\Metrics\ServerResource;
7+
use Illuminate\Support\Facades\Cache;
98
use Laravel\Nova\Dashboard;
9+
use Laravelwebdev\ListCard\ListCard;
1010
use Laravelwebdev\SystemInfo\SystemInfo;
11+
use Spatie\Backup\BackupDestination\Backup;
12+
use Spatie\Backup\BackupDestination\BackupDestination;
13+
use Spatie\Backup\Helpers\Format;
1114

1215
class SystemHealth extends Dashboard
1316
{
@@ -18,18 +21,63 @@ class SystemHealth extends Dashboard
1821
*/
1922
public function cards(): array
2023
{
24+
$outdated = array_map(fn ($package) => [
25+
'title' => $package['name'],
26+
'description' => 'Installed: '.$package['version'].' | Latest: '.$package['latest'],
27+
], Api::getComposerOutdatedPackages());
28+
29+
$disk = config('backup.backup.destination.disks')[0] ?? 'local';
30+
$backupDestination = BackupDestination::create($disk, config('backup.backup.name'));
31+
$backups = Cache::remember("backups-{$disk}", now()->addSeconds(4), function () use ($backupDestination) {
32+
return $backupDestination
33+
->backups()
34+
->map(function (Backup $backup) {
35+
$size = method_exists($backup, 'sizeInBytes') ? $backup->sizeInBytes() : $backup->size();
36+
37+
return [
38+
'path' => $backup->path(),
39+
'date' => $backup->date()->format('j F Y H:i:s'),
40+
'size' => Format::humanReadableSize($size),
41+
];
42+
})
43+
->toArray();
44+
});
45+
46+
$backuplist = array_map(function ($backup) {
47+
return [
48+
'title' => $backup['path'],
49+
'description' => 'Created: '.$backup['date'].', Size: '.$backup['size'],
50+
'icon' => 'arrow-down',
51+
'url' => config('app.url').config('nova.path').'/backup/download/'.basename($backup['path']),
52+
];
53+
}, $backups);
54+
55+
$issues = array_map(function ($issue) {
56+
return [
57+
'title' => ucwords($issue['type']).' ('.$issue['count'].')',
58+
'description' => $issue['title'],
59+
];
60+
}, Api::getSentryUnresolvedIssues());
61+
2162
return [
2263
ServerResource::make()->refreshIntervalSeconds(60),
2364
ServerResource::make('inode')->refreshIntervalSeconds(60),
2465
ServerResource::make('backup')->help('')->refreshIntervalSeconds(60),
25-
SystemInfo::make()->versions()->width('1/2')->refreshIntervalSeconds(60),
26-
BackupsTable::make()->width('1/2')
27-
->emptyText('No backups found.')
28-
->refreshIntervalSeconds(60),
29-
OutdatedTable::make()->width('1/2')
66+
SystemInfo::make()->versions()->width('1/2'),
67+
ListCard::make()
68+
->width('1/2')
69+
->title('Backups')
70+
->items($backuplist)
71+
->emptyText('No Backup Found'),
72+
ListCard::make()
73+
->width('1/2')
74+
->title('Outdated Packages')
75+
->items($outdated)
3076
->emptyText('All packages are already up to date.'),
31-
IssuesTable::make()->width('1/2')
32-
->refreshIntervalSeconds(60)
77+
ListCard::make()
78+
->width('1/2')
79+
->title('Unresolved Issues')
80+
->items($issues)
3381
->emptyText('No issues found.'),
3482
];
3583
}

0 commit comments

Comments
 (0)