From 64092d3abc0371a7fa1dfcec686eaf696466c546 Mon Sep 17 00:00:00 2001 From: I-Fun Date: Sun, 5 Apr 2026 10:45:49 +0700 Subject: [PATCH] feat: implement Alpine.js modal for content details and migrate to SortableJS for kanban board functionality --- app/Http/Controllers/EventController.php | 10 +- resources/views/content/index.blade.php | 126 +++- resources/views/schedule/create.blade.php | 826 +++++++++++----------- resources/views/schedule/index.blade.php | 37 + 4 files changed, 575 insertions(+), 424 deletions(-) diff --git a/app/Http/Controllers/EventController.php b/app/Http/Controllers/EventController.php index c05c48c..9920f75 100644 --- a/app/Http/Controllers/EventController.php +++ b/app/Http/Controllers/EventController.php @@ -70,7 +70,15 @@ class EventController extends Controller ], ]); - return view('schedule.index', compact('events', 'clients', 'calendarEvents', 'categoryTree')); + $holidays = \Illuminate\Support\Facades\Cache::remember('indonesian_holidays', 86400, function() { + $url = "https://libur.deno.dev/api"; + $response = @file_get_contents($url); + if ($response === false) return []; + $data = json_decode($response, true); + return is_array($data) ? $data : []; + }); + + return view('schedule.index', compact('events', 'clients', 'calendarEvents', 'categoryTree', 'holidays')); } public function store(Request $request): RedirectResponse diff --git a/resources/views/content/index.blade.php b/resources/views/content/index.blade.php index cfb9483..c3019fa 100644 --- a/resources/views/content/index.blade.php +++ b/resources/views/content/index.blade.php @@ -50,16 +50,28 @@ {{-- Sortable items container --}} -
+
@foreach($col['items'] as $brief)
+ cursor-grab active:cursor-grabbing hover:shadow-md transition-shadow kanban-item" + data-id="{{ $brief->id }}">
{{ $brief->platform_icon }} - {{ $brief->title }} @@ -89,24 +101,106 @@
@endforeach + + {{-- Content Detail Request Modal --}} +
@push('scripts') + diff --git a/resources/views/schedule/create.blade.php b/resources/views/schedule/create.blade.php index 3227868..88c3991 100644 --- a/resources/views/schedule/create.blade.php +++ b/resources/views/schedule/create.blade.php @@ -5,437 +5,449 @@ @section('page-subtitle', 'Schedule a new task, meeting, or posting') @section('content') -
- +
+ -
-
- @csrf - - +
+ + @csrf + + - {{-- Title --}} -
- - - @error('title')

{{ $message }}

@enderror -
- -
- {{-- Type --}} -
- - -
- - {{-- Client --}} -
- - -
- - {{-- Quick New Client mini-form --}} - - - {{-- Category --}} -
- - -
- - {{-- Quick New Category mini-form --}} - - - {{-- Contract warning --}} - - - {{-- Start Date --}} + {{-- Title --}}
- -
-
- - + + @error('title')

{{ $message }}

@enderror
- {{-- End Date --}} -
- - -
-
- - -
- - {{-- Location --}} -
- - -
-
- - {{-- Description --}} -
- - -
- - {{-- Color --}} -
- - -
- - -
-
- - {{-- Priority --}} -
- - -
- - {{-- Notes --}} -
- - -
- - {{-- ── Add to Content Board ──────────────────────────────── --}} -
-
- - -
-
+
+ {{-- Type --}}
- - + @foreach(['task' => 'πŸ“‹ Task', 'meeting' => '🀝 Meeting', 'deadline' => '⏰ Deadline', 'posting' => 'πŸ“Έ Posting'] as $val => $label) + + @endforeach
+ + {{-- Client --}}
- - + + + @foreach($clients as $client) + + @endforeach
-

- A Drafting card will be created in your Content Board with this event's title and date. -

-
-
- {{-- ── Brand Contract ────────────────────────────────────── --}} -
-
- - -
-
+ {{-- Quick New Client mini-form --}} + + + {{-- Category --}}
- - + + +
+ + {{-- Quick New Category mini-form --}} + + + {{-- Contract warning --}} + + + {{-- Start Date --}} +
+ +
- - + + +
+ + {{-- End Date --}} +
+ +
- - + + +
+ + {{-- Location --}} +
+ +
-
-
- - - Cancel - -
- + {{-- Description --}} +
+ + +
+ + {{-- Color --}} +
+ + +
+ + +
+
+ + {{-- Priority --}} +
+ + +
+ + {{-- Notes --}} +
+ + +
+ + {{-- ── Add to Content Board ──────────────────────────────── --}} +
+
+ + +
+
+
+ + +
+
+ + +
+

+ A Drafting card will be created in your Content Board with this event's title and date. +

+
+
+ + {{-- ── Brand Contract ────────────────────────────────────── --}} +
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ + + Cancel + +
+ +
-
-@push('scripts') - -@endpush -@endsection + document.getElementById('start_time_hidden').value = startDate + 'T' + startTime; + if (endDate) { + document.getElementById('end_time_hidden').value = endDate + 'T' + endTime; + } + }); + + @endpush +@endsection \ No newline at end of file diff --git a/resources/views/schedule/index.blade.php b/resources/views/schedule/index.blade.php index 23b89d5..9904576 100644 --- a/resources/views/schedule/index.blade.php +++ b/resources/views/schedule/index.blade.php @@ -104,6 +104,43 @@ document.addEventListener('DOMContentLoaded', function () { } }, + dayCellDidMount(info) { + const holidays = @json($holidays ?? []); + const holidayMap = {}; + holidays.forEach(h => holidayMap[h.date] = h.name); + + const year = info.date.getFullYear(); + const month = String(info.date.getMonth() + 1).padStart(2, '0'); + const day = String(info.date.getDate()).padStart(2, '0'); + const dateStr = `${year}-${month}-${day}`; + + if (holidayMap[dateStr]) { + const frame = info.el.querySelector('.fc-daygrid-day-frame'); + if (frame) { + // Update background color for the highlighted box + frame.style.backgroundColor = '#fff0f0'; // Light red highlighted box + frame.style.position = 'relative'; // Required for absolute positioning of text + + // Add the holiday text to the top-left corner + const holidayEl = document.createElement('div'); + holidayEl.textContent = holidayMap[dateStr]; + holidayEl.style.position = 'absolute'; + holidayEl.style.top = '4px'; + holidayEl.style.left = '4px'; + holidayEl.style.color = '#ef4444'; // Red text + holidayEl.style.fontSize = '0.70rem'; // Small text + holidayEl.style.fontWeight = '600'; + holidayEl.style.whiteSpace = 'nowrap'; + holidayEl.style.overflow = 'hidden'; + holidayEl.style.textOverflow = 'ellipsis'; + holidayEl.style.maxWidth = '75%'; // Prevent it from overlapping with the date number (usually on right) + holidayEl.style.zIndex = '1'; + + frame.appendChild(holidayEl); + } + } + }, + eventDrop(info) { fetch(`/schedule/${info.event.id}/dates`, { method: 'PATCH',