Skip to content

Commit bdd2aa7

Browse files
committed
✅ Integrity Verified
1 parent 3b45298 commit bdd2aa7

18 files changed

Lines changed: 585 additions & 277 deletions
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
namespace App\Livewire;
4+
5+
use Livewire\Component;
6+
use App\Models\Attendance;
7+
use Illuminate\Support\Facades\Auth;
8+
use Carbon\Carbon;
9+
10+
class AttendanceCalendar extends Component
11+
{
12+
public $month;
13+
public $year;
14+
public $daysInMonth = [];
15+
16+
public function mount()
17+
{
18+
$this->month = Carbon::now()->month;
19+
$this->year = Carbon::now()->year;
20+
$this->generateCalendar();
21+
}
22+
23+
public function generateCalendar()
24+
{
25+
$date = Carbon::createFromDate($this->year, $this->month, 1);
26+
$daysInMonthCount = $date->daysInMonth;
27+
28+
$attendances = Attendance::where('user_id', Auth::id())
29+
->whereMonth('date', $this->month)
30+
->whereYear('date', $this->year)
31+
->get()
32+
->keyBy('date');
33+
34+
$this->daysInMonth = [];
35+
36+
// Padding awal (agar hari pertama sesuai dengan nama hari)
37+
$firstDayOfWeek = $date->dayOfWeek; // 0 (Sun) to 6 (Sat)
38+
for ($i = 0; $i < $firstDayOfWeek; $i++) {
39+
$this->daysInMonth[] = null;
40+
}
41+
42+
for ($day = 1; $day <= $daysInMonthCount; $day++) {
43+
$currentDate = Carbon::createFromDate($this->year, $this->month, $day)->format('Y-m-d');
44+
$this->daysInMonth[] = [
45+
'day' => $day,
46+
'attendance' => $attendances->get($currentDate)
47+
];
48+
}
49+
}
50+
51+
public function prevMonth()
52+
{
53+
$date = Carbon::createFromDate($this->year, $this->month, 1)->subMonth();
54+
$this->month = $date->month;
55+
$this->year = $date->year;
56+
$this->generateCalendar();
57+
}
58+
59+
public function nextMonth()
60+
{
61+
$date = Carbon::createFromDate($this->year, $this->month, 1)->addMonth();
62+
$this->month = $date->month;
63+
$this->year = $date->year;
64+
$this->generateCalendar();
65+
}
66+
67+
public function render()
68+
{
69+
return view('livewire.attendance-calendar')->layout('components.layouts.app');
70+
}
71+
}

app/Livewire/SessionManager.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace App\Livewire;
4+
5+
use Livewire\Component;
6+
use Illuminate\Support\Facades\DB;
7+
use Illuminate\Support\Facades\Auth;
8+
use Illuminate\Support\Facades\Session;
9+
10+
class SessionManager extends Component
11+
{
12+
public function getSessionsProperty()
13+
{
14+
return DB::table('sessions')
15+
->where('user_id', Auth::id())
16+
->orderBy('last_activity', 'desc')
17+
->get();
18+
}
19+
20+
public function logoutOtherDevices()
21+
{
22+
$currentSessionId = Session::getId();
23+
24+
DB::table('sessions')
25+
->where('user_id', Auth::id())
26+
->where('id', '!=', $currentSessionId)
27+
->delete();
28+
29+
$this->dispatch('flash-message', text: 'Semua sesi di perangkat lain telah diakhiri.');
30+
}
31+
32+
public function logoutSession($id)
33+
{
34+
DB::table('sessions')->where('id', $id)->delete();
35+
$this->dispatch('flash-message', text: 'Sesi perangkat berhasil diakhiri.');
36+
}
37+
38+
public function render()
39+
{
40+
return view('livewire.session-manager');
41+
}
42+
}

app/Livewire/SystemSettings.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
namespace App\Livewire;
4+
5+
use Livewire\Component;
6+
use App\Models\Setting;
7+
use Illuminate\Support\Facades\Auth;
8+
9+
class SystemSettings extends Component
10+
{
11+
public $office_latitude;
12+
public $office_longitude;
13+
public $geofence_radius;
14+
public $allowed_ips;
15+
public $app_name;
16+
17+
public function mount()
18+
{
19+
if (Auth::user()->role !== 'admin') abort(403);
20+
21+
$this->app_name = Setting::where('key', 'app_name')->first()?->value ?? config('app.name');
22+
$this->office_latitude = Setting::where('key', 'office_latitude')->first()?->value ?? config('app.office_latitude');
23+
$this->office_longitude = Setting::where('key', 'office_longitude')->first()?->value ?? config('app.office_longitude');
24+
$this->geofence_radius = Setting::where('key', 'geofence_radius')->first()?->value ?? 100;
25+
$this->allowed_ips = Setting::where('key', 'allowed_ips')->first()?->value ?? '';
26+
}
27+
28+
public function save()
29+
{
30+
$this->validate([
31+
'office_latitude' => 'required|numeric',
32+
'office_longitude' => 'required|numeric',
33+
'geofence_radius' => 'required|integer|min:10',
34+
'app_name' => 'required|string',
35+
]);
36+
37+
$settings = [
38+
'app_name' => $this->app_name,
39+
'office_latitude' => $this->office_latitude,
40+
'office_longitude' => $this->office_longitude,
41+
'geofence_radius' => $this->geofence_radius,
42+
'allowed_ips' => $this->allowed_ips,
43+
];
44+
45+
foreach ($settings as $key => $value) {
46+
Setting::updateOrCreate(['key' => $key], ['value' => $value]);
47+
}
48+
49+
$this->dispatch('flash-message', text: 'Konfigurasi sistem berhasil diperbarui secara global.');
50+
}
51+
52+
public function render()
53+
{
54+
return view('livewire.system-settings')->layout('components.layouts.app');
55+
}
56+
}

app/Models/Setting.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace App\Models;
4+
5+
use Illuminate\Database\Eloquent\Model;
6+
7+
class Setting extends Model
8+
{
9+
//
10+
}

app/Providers/AppServiceProvider.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
use Illuminate\Support\ServiceProvider;
66

7+
use Illuminate\Support\Facades\Schema;
8+
use App\Models\Setting;
9+
710
class AppServiceProvider extends ServiceProvider
811
{
912
/**
@@ -19,6 +22,21 @@ public function register(): void
1922
*/
2023
public function boot(): void
2124
{
22-
//
25+
// Overwrite config with database settings if table exists
26+
if (Schema::hasTable('settings')) {
27+
$settings = Setting::all();
28+
29+
foreach ($settings as $setting) {
30+
if ($setting->key === 'app_name') {
31+
config(['app.name' => $setting->value]);
32+
} elseif ($setting->key === 'office_latitude') {
33+
config(['app.office_latitude' => $setting->value]);
34+
} elseif ($setting->key === 'office_longitude') {
35+
config(['app.office_longitude' => $setting->value]);
36+
} elseif ($setting->key === 'allowed_ips') {
37+
config(['app.allowed_ips' => $setting->value]);
38+
}
39+
}
40+
}
2341
}
2442
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
public function up(): void
10+
{
11+
Schema::create('settings', function (Blueprint $table) {
12+
$table->id();
13+
$table->string('key')->unique();
14+
$table->text('value')->nullable();
15+
$table->string('group')->default('general');
16+
$table->timestamps();
17+
});
18+
}
19+
20+
public function down(): void
21+
{
22+
Schema::dropIfExists('settings');
23+
}
24+
};

resources/views/components/layouts/app.blade.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<head>
44
<meta charset="utf-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6-
<title>{{ $title ?? 'SIMPEG Lapas' }}</title>
6+
<title>{{ $title ?? config('app.name') }}</title>
77

88
{{-- CDN Libraries --}}
99
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
@@ -90,10 +90,10 @@
9090
{{-- Logo --}}
9191
<div class="shrink-0 flex items-center gap-3">
9292
<div class="h-10 w-10 bg-gradient-to-br from-indigo-600 to-purple-600 rounded-xl flex items-center justify-center text-white font-bold text-xl shadow-lg shadow-indigo-500/30">
93-
S
93+
{{ substr(config('app.name'), 0, 1) }}
9494
</div>
95-
<span class="text-2xl font-extrabold text-gray-800 tracking-tight hidden md:block">
96-
SIMPEG <span class="text-indigo-600">Lapas</span>
95+
<span class="text-2xl font-extrabold text-gray-800 tracking-tight hidden md:block uppercase">
96+
{{ config('app.name') }}
9797
</span>
9898
</div>
9999

@@ -131,9 +131,9 @@
131131
<span class="text-lg group-hover:scale-110 transition-transform">📝</span>
132132
<span class="whitespace-nowrap">Laporan Kejadian</span>
133133
</a>
134-
<a href="/rekap-absensi" wire:navigate class="group flex items-center gap-2 px-4 py-2 rounded-full text-sm font-bold transition-all {{ request()->routeIs('rekap') ? 'bg-indigo-50 text-indigo-700 shadow-sm ring-1 ring-indigo-200' : 'text-gray-500 hover:bg-gray-50 hover:text-indigo-600' }}">
134+
<a href="/kalender-absen" wire:navigate class="group flex items-center gap-2 px-4 py-2 rounded-full text-sm font-bold transition-all {{ request()->routeIs('attendance.calendar') ? 'bg-indigo-50 text-indigo-700 shadow-sm ring-1 ring-indigo-200' : 'text-gray-500 hover:bg-gray-50 hover:text-indigo-600' }}">
135135
<span class="text-lg group-hover:scale-110 transition-transform">📊</span>
136-
<span class="whitespace-nowrap">Rekap</span>
136+
<span class="whitespace-nowrap">Activity</span>
137137
</a>
138138
@if(auth()->check() && strtolower(trim(auth()->user()->role)) === 'admin')
139139
<a href="{{ route('admin.dashboard') }}" wire:navigate class="group flex items-center gap-2 px-4 py-2 rounded-full text-sm font-bold transition-all {{ request()->routeIs('admin.dashboard') ? 'bg-indigo-50 text-indigo-700 shadow-sm ring-1 ring-indigo-200' : 'text-gray-500 hover:bg-gray-50 hover:text-indigo-600' }}">
@@ -152,6 +152,10 @@
152152
<span class="text-lg group-hover:scale-110 transition-transform">📍</span>
153153
<span class="whitespace-nowrap">Plotting Pos</span>
154154
</a>
155+
<a href="{{ route('settings') }}" wire:navigate class="group flex items-center gap-2 px-4 py-2 rounded-full text-sm font-bold transition-all {{ request()->routeIs('settings') ? 'bg-indigo-50 text-indigo-700 shadow-sm ring-1 ring-indigo-200' : 'text-gray-500 hover:bg-gray-50 hover:text-indigo-600' }}">
156+
<span class="text-lg group-hover:scale-110 transition-transform">⚙️</span>
157+
<span class="whitespace-nowrap">Settings</span>
158+
</a>
155159
@endif
156160
</div>
157161
</div>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
use Livewire\Component;
4+
5+
new class extends Component
6+
{
7+
//
8+
};
9+
?>
10+
11+
<div>
12+
{{-- The biggest battle is the war against ignorance. - Mustafa Kemal Atatürk --}}
13+
</div>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
use Livewire\Component;
4+
5+
new class extends Component
6+
{
7+
//
8+
};
9+
?>
10+
11+
<div>
12+
{{-- I have not failed. I've just found 10,000 ways that won't work. - Thomas Edison --}}
13+
</div>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
use Livewire\Component;
4+
5+
new class extends Component
6+
{
7+
//
8+
};
9+
?>
10+
11+
<div>
12+
{{-- Let all your things have their places; let each part of your business have its time. - Benjamin Franklin --}}
13+
</div>

0 commit comments

Comments
 (0)