diff --git a/Modules/Helpdesk/Livewire/TicketCreate.php b/Modules/Helpdesk/Livewire/TicketCreate.php index 216f0730..72a1ad73 100644 --- a/Modules/Helpdesk/Livewire/TicketCreate.php +++ b/Modules/Helpdesk/Livewire/TicketCreate.php @@ -102,6 +102,32 @@ final class TicketCreate extends Component return $this->redirectRoute('helpdesk.tickets.index', navigate: true); } + + /** + * Clear the create form, including Select2 and Flatpickr browser widgets. + */ + public function clearForm(): void + { + $this->resetErrorBag(); + $this->resetValidation(); + + $this->subject = ''; + $this->body = ''; + $this->company_id = null; + $this->board_id = null; + $this->priority_id = null; + $this->category_id = null; + $this->project_id = null; + $this->product_id = null; + $this->team_id = null; + $this->due_at = null; + $this->tag_ids = []; + $this->attachments = []; + + $this->dispatch('helpdesk-form-cleared'); + $this->dispatch('helpdesk-editor-reset', model: 'body'); + } + public function render(): View { return view('helpdesk::livewire.ticket-create', [ diff --git a/Modules/Helpdesk/Livewire/TicketEdit.php b/Modules/Helpdesk/Livewire/TicketEdit.php index 6bcf0719..a433be58 100644 --- a/Modules/Helpdesk/Livewire/TicketEdit.php +++ b/Modules/Helpdesk/Livewire/TicketEdit.php @@ -130,6 +130,34 @@ final class TicketEdit extends Component return redirect()->route('helpdesk.tickets.show', $fresh); } + + /** + * Clear the edit form, including Select2 and Flatpickr browser widgets. + */ + public function clearForm(): void + { + $this->authorize('update', $this->ticket); + $this->resetErrorBag(); + $this->resetValidation(); + + $this->subject = ''; + $this->body = ''; + $this->company_id = null; + $this->status_id = null; + $this->board_id = null; + $this->priority_id = null; + $this->category_id = null; + $this->project_id = null; + $this->product_id = null; + $this->team_id = null; + $this->agent_id = null; + $this->due_at = null; + $this->tag_ids = []; + + $this->dispatch('helpdesk-form-cleared'); + $this->dispatch('helpdesk-editor-reset', model: 'body'); + } + public function render(): View { return view('helpdesk::livewire.ticket-edit', [ diff --git a/Modules/Helpdesk/Resources/assets/css/app.css b/Modules/Helpdesk/Resources/assets/css/app.css index c908ab89..11ef032b 100644 --- a/Modules/Helpdesk/Resources/assets/css/app.css +++ b/Modules/Helpdesk/Resources/assets/css/app.css @@ -582,3 +582,61 @@ top: 50% !important; transform: translateY(-50%) !important; } + +/* Helpdesk Flatpickr date picker */ +.flatpickr-calendar { + border: 1px solid rgb(63 63 70); + background: rgb(24 24 27); + color: rgb(244 244 245); + box-shadow: 0 20px 45px rgb(0 0 0 / 0.35); +} + +.flatpickr-calendar.arrowTop::before, +.flatpickr-calendar.arrowTop::after, +.flatpickr-calendar.arrowBottom::before, +.flatpickr-calendar.arrowBottom::after { + border-bottom-color: rgb(24 24 27); + border-top-color: rgb(24 24 27); +} + +.flatpickr-months, +.flatpickr-months .flatpickr-month, +.flatpickr-current-month .flatpickr-monthDropdown-months, +.flatpickr-current-month input.cur-year { + background: rgb(24 24 27); + color: rgb(244 244 245); +} + +.flatpickr-weekday, +span.flatpickr-weekday { + color: rgb(161 161 170); +} + +.flatpickr-day { + color: rgb(228 228 231); +} + +.flatpickr-day:hover, +.flatpickr-day:focus { + border-color: rgb(59 130 246); + background: rgb(39 39 42); + color: rgb(255 255 255); +} + +.flatpickr-day.selected, +.flatpickr-day.startRange, +.flatpickr-day.endRange { + border-color: rgb(37 99 235); + background: rgb(37 99 235); + color: rgb(255 255 255); +} + +.flatpickr-day.today { + border-color: rgb(34 197 94); +} + +.flatpickr-day.flatpickr-disabled, +.flatpickr-day.prevMonthDay, +.flatpickr-day.nextMonthDay { + color: rgb(113 113 122); +} diff --git a/Modules/Helpdesk/Resources/assets/js/app.js b/Modules/Helpdesk/Resources/assets/js/app.js index ec2a020b..f801a102 100644 --- a/Modules/Helpdesk/Resources/assets/js/app.js +++ b/Modules/Helpdesk/Resources/assets/js/app.js @@ -1,30 +1,130 @@ import './bootstrap'; import $ from 'jquery'; +import select2 from 'select2/dist/js/select2.full.js'; +import flatpickr from 'flatpickr'; +import 'flatpickr/dist/flatpickr.css'; + window.$ = $; window.jQuery = $; -import select2 from 'select2/dist/js/select2.full.js'; + select2(window, $); -function initialiseHelpdeskSelects() -{ - console.log('initialising select2'); + +function livewireComponentFor(element) { + const componentRoot = element.closest('[wire\\:id]'); + + if (!componentRoot || ! window.Livewire) { + return null; + } + + return window.Livewire.find(componentRoot.getAttribute('wire:id')); +} + +function setLivewireProperty(element, model, value) { + const component = livewireComponentFor(element); + + if (!component || !model) { + return; + } + + component.set(model, value === '' ? null : value); +} + +function initialiseHelpdeskSelects() { $('[data-helpdesk-select2]').each(function () { - const $select = $(this); + const select = this; + const $select = $(select); + const placeholder = $select.data('placeholder') || $select.find('option[value=""]').first().text() || 'Select option'; + if ($select.hasClass('select2-hidden-accessible')) { return; } + + if (!$select.find('option[value=""]').length) { + $select.prepend(new Option('', '', false, false)); + } + $select.select2({ width: '100%', allowClear: true, + placeholder, + }); + + $select.on('change.helpdesk-select2', function () { + setLivewireProperty(select, $select.data('wire-model'), $select.val()); }); }); } -document.addEventListener('DOMContentLoaded', initialiseHelpdeskSelects); -document.addEventListener('livewire:navigated', initialiseHelpdeskSelects); -document.addEventListener('livewire:init', () => { +function clearHelpdeskSelects(root = document) { + $(root).find('[data-helpdesk-select2]').each(function () { + const $select = $(this); + + $select.val(null); + $select.trigger('change.select2'); + $select.trigger('change.helpdesk-select2'); + $select.trigger('change'); + }); +} + +function initialiseHelpdeskDatePickers() { + document.querySelectorAll('[data-helpdesk-flatpickr]').forEach((input) => { + if (input._helpdeskFlatpickr) { + return; + } + + input._helpdeskFlatpickr = flatpickr(input, { + allowInput: true, + altInput: true, + altFormat: 'd M Y', + dateFormat: 'Y-m-d', + disableMobile: false, + onChange: (_selectedDates, dateText) => { + setLivewireProperty(input, input.dataset.wireModel, dateText || null); + }, + onClose: (_selectedDates, dateText) => { + setLivewireProperty(input, input.dataset.wireModel, dateText || null); + }, + }); + }); +} + +function clearHelpdeskDatePickers(root = document) { + root.querySelectorAll('[data-helpdesk-flatpickr]').forEach((input) => { + if (input._helpdeskFlatpickr) { + input._helpdeskFlatpickr.clear(); + } + + input.value = ''; + setLivewireProperty(input, input.dataset.wireModel, null); + }); +} + +function initialiseHelpdeskFormControls() { initialiseHelpdeskSelects(); + initialiseHelpdeskDatePickers(); +} + +function clearHelpdeskFormControls() { + clearHelpdeskSelects(); + clearHelpdeskDatePickers(); +} + +window.initialiseHelpdeskFormControls = initialiseHelpdeskFormControls; +window.clearHelpdeskFormControls = clearHelpdeskFormControls; + +document.addEventListener('DOMContentLoaded', initialiseHelpdeskFormControls); +document.addEventListener('livewire:navigated', initialiseHelpdeskFormControls); +document.addEventListener('helpdesk-form-cleared', clearHelpdeskFormControls); + +document.addEventListener('livewire:init', () => { + initialiseHelpdeskFormControls(); + Livewire.hook('morphed', () => { - initialiseHelpdeskSelects(); + initialiseHelpdeskFormControls(); + }); + + Livewire.on('helpdesk-form-cleared', () => { + clearHelpdeskFormControls(); }); }); diff --git a/Modules/Helpdesk/Resources/views/components/date-picker.blade.php b/Modules/Helpdesk/Resources/views/components/date-picker.blade.php new file mode 100644 index 00000000..f514c6ed --- /dev/null +++ b/Modules/Helpdesk/Resources/views/components/date-picker.blade.php @@ -0,0 +1,33 @@ +@props([ + 'id', + 'model', + 'label' => null, + 'required' => false, + 'placeholder' => 'Select date', +]) + +
+ @if ($label) + + @endif + +
+ except('value')->merge([ + 'class' => 'block w-full rounded-xl border border-zinc-700 bg-zinc-950 px-4 py-3 text-sm text-zinc-100 shadow-sm outline-none transition-colors duration-150 placeholder:text-zinc-500 focus:border-blue-500 focus:ring-2 focus:ring-blue-500/40', + ]) }} + /> +
+
diff --git a/Modules/Helpdesk/Resources/views/livewire/ticket-create.blade.php b/Modules/Helpdesk/Resources/views/livewire/ticket-create.blade.php index d03ef7f7..1e13502e 100644 --- a/Modules/Helpdesk/Resources/views/livewire/ticket-create.blade.php +++ b/Modules/Helpdesk/Resources/views/livewire/ticket-create.blade.php @@ -3,6 +3,10 @@ 'resources/css/app.css', 'resources/js/app.js', ]) + @vite([ + 'Resources/assets/css/app.css', + 'Resources/assets/js/app.js', + ], 'build/helpdesk') @include('helpdesk::partials.page-header', [ 'eyebrow' => 'Helpdesk', @@ -51,6 +55,7 @@ + @foreach ($boards as $board) @endforeach @@ -100,6 +107,7 @@ @@ -173,6 +183,7 @@ + @error('due_at')

{{ $message }}

diff --git a/Modules/Helpdesk/Resources/views/livewire/ticket-edit.blade.php b/Modules/Helpdesk/Resources/views/livewire/ticket-edit.blade.php index cbc73e25..c8f48d26 100644 --- a/Modules/Helpdesk/Resources/views/livewire/ticket-edit.blade.php +++ b/Modules/Helpdesk/Resources/views/livewire/ticket-edit.blade.php @@ -3,6 +3,10 @@ 'resources/css/app.css', 'resources/js/app.js', ]) + @vite([ + 'Resources/assets/css/app.css', + 'Resources/assets/js/app.js', + ], 'build/helpdesk') @include('helpdesk::partials.page-header', [ 'eyebrow' => 'Helpdesk', @@ -70,6 +74,7 @@ + @foreach ($statuses as $status) @endforeach @@ -142,10 +150,12 @@ @@ -213,6 +225,7 @@ @@ -300,9 +314,13 @@
- - - + @error('due_at')

{{ $message }}

diff --git a/Modules/Helpdesk/changelog.yaml b/Modules/Helpdesk/changelog.yaml index d1226540..a2bae294 100644 --- a/Modules/Helpdesk/changelog.yaml +++ b/Modules/Helpdesk/changelog.yaml @@ -174,3 +174,12 @@ versions: - Fixed malformed Helpdesk settings action buttons that caused Blade parse errors. - Applied explicit coloured action buttons across settings tables, settings forms and Kanban board configuration actions. - Kept module.json version in sync with changelog.yaml. + + + "1.3.7": + changed: + - Fixed ticket create/edit clear actions by adding public Livewire clearForm methods to both components. + - Stabilised Select2 clearing by loading module assets on ticket forms, adding placeholder support, manually syncing Select2 changes back to Livewire and clearing browser widgets after Livewire reset events. + - Replaced native due date inputs on ticket create/edit with a reusable Helpdesk Flatpickr date-picker component. + - Added Flatpickr module dependency and dark Helpdesk calendar styling. + - Kept module.json version in sync with changelog.yaml. diff --git a/Modules/Helpdesk/module.json b/Modules/Helpdesk/module.json index edc046c4..1e4d3519 100644 --- a/Modules/Helpdesk/module.json +++ b/Modules/Helpdesk/module.json @@ -22,5 +22,5 @@ "Modules\\Helpdesk\\Providers\\HelpdeskServiceProvider" ], "files": [], - "version": "1.3.6" + "version": "1.3.7" } diff --git a/Modules/Helpdesk/package.json b/Modules/Helpdesk/package.json index aa9c3fbb..140e80d2 100644 --- a/Modules/Helpdesk/package.json +++ b/Modules/Helpdesk/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "jquery": "3.7.1", - "select2": "^4.1.0" + "select2": "^4.1.0", + "flatpickr": "^4.6.13" } }