feat(tasks): complete task management system with Kanban, Calendar, notifications

- Add Task model with subtasks, priorities, status transitions, dates, hours
- Add Comment polymorphic model for tasks/issues/projects
- Livewire components: TaskManager (list+filters), TaskForm (modal), TaskDetail, TaskKanban (drag&drop), TaskCalendar (FullCalendar)
- TaskPolicy with permissions (view/create/edit/delete/assign/manage all)
- Notifications: assigned, status change, overdue, comment added
- Daily overdue notification job scheduled
- Dashboard widget unifies IssueTask + Task
- i18n: en/es/fr/ru (393 keys each)
- Routes, navigation, offline sync support
- 101 tests passing, Pint compliant on new files
This commit is contained in:
Javier Braña
2026-08-03 13:44:10 +02:00
parent a65d4b12f2
commit ba614bddbc
62 changed files with 5878 additions and 382 deletions
@@ -1,12 +1,33 @@
<div class="flex items-center gap-1"
x-on:locale-changed.window="window.location.reload()">
@foreach(['es' => ['flag' => 'es.svg', 'label' => 'ES'], 'en' => ['flag' => 'gb.svg', 'label' => 'EN']] as $code => $lang)
<button wire:click="switchLanguage('{{ $code }}')"
class="btn btn-xs gap-1.5 {{ $currentLocale === $code ? 'btn-primary' : 'btn-ghost' }}"
title="{{ __('Language') }}: {{ __($code === 'en' ? 'English' : 'Spanish') }}">
<img src="{{ asset('images/flags/' . $lang['flag']) }}"
class="w-4 h-auto rounded-sm border border-base-300" alt="{{ $lang['label'] }}">
{{ $lang['label'] }}
<x-dropdown align="right" width="48">
<x-slot name="trigger">
<button class="btn btn-ghost btn-sm gap-2" type="button">
<img src="{{ asset('images/flags/' . ($languages[$currentLocale]['flag'] ?? 'gb.svg')) }}"
class="w-5 h-4 rounded-sm border border-base-300"
alt="{{ $languages[$currentLocale]['name'] ?? 'English' }}">
<span class="hidden sm:inline">{{ $languages[$currentLocale]['name'] ?? 'English' }}</span>
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
@endforeach
</div>
</x-slot>
<x-slot name="content">
<div class="py-1">
@foreach($languages as $code => $lang)
<button wire:click="switchLanguage('{{ $code }}')"
class="flex items-center gap-2 w-full px-3 py-2 text-sm hover:bg-base-200 rounded-md {{ $currentLocale === $code ? 'bg-primary/10 text-primary font-medium' : 'text-base-content' }}"
type="button">
<img src="{{ asset('images/flags/' . $lang['flag']) }}"
class="w-5 h-4 rounded-sm border border-base-300"
alt="{{ $lang['name'] }}">
<span>{{ $lang['name'] }}</span>
@if($currentLocale === $code)
<svg class="ml-auto w-4 h-4 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
</svg>
@endif
</button>
@endforeach
</div>
</x-slot>
</x-dropdown>