Create reusable Livewire component for project edit tabs and replace manual tabs implementation

This commit is contained in:
2026-05-12 12:06:17 +02:00
parent 65254a0dfa
commit 0bc3ca3d3e
3 changed files with 163 additions and 77 deletions
@@ -0,0 +1,120 @@
<div>
<!-- Tabs -->
<div class="tab-toggle">
<input type="radio" name="tabs-project-edit-{{ $project->id }}" id="tab-project-data-{{ $project->id }}"
{{ $activeTab === 'project-data' ? 'checked' : '' }} class="tab-toggle" />
<label for="tab-project-data-{{ $project->id }}" class="tab {{ $activeTab === 'project-data' ? 'tab-active' : '' }}">
{{ __('Project Data') }}
</label>
<input type="radio" name="tabs-project-edit-{{ $project->id }}" id="tab-phases-{{ $project->id }}"
{{ $activeTab === 'phases' ? 'checked' : '' }} class="tab-toggle" />
<label for="tab-phases-{{ $project->id }}" class="tab {{ $activeTab === 'phases' ? 'tab-active' : '' }}">
{{ __('Phases') }}
</label>
<input type="radio" name="tabs-project-edit-{{ $project->id }}" id="tab-users-{{ $project->id }}"
{{ $activeTab === 'users' ? 'checked' : '' }} class="tab-toggle" />
<label for="tab-users-{{ $project->id }}" class="tab {{ $activeTab === 'users' ? 'tab-active' : '' }}">
{{ __('Users') }}
</label>
</div>
<!-- Tab Content -->
<div class="tab-content">
<!-- Project Data Tab -->
<div id="tab-project-data-{{ $project->id }}"
class="tab-content-base p-4 {{ $activeTab === 'project-data' ? '' : 'hidden' }}">
<form wire:submit.prevent="updateProject" class="space-y-4">
@csrf
@method('PUT')
<div>
<label class="label">{{ __('Name') }}</label>
<input type="text" name="name"
wire:model.debounce.500ms="project.name"
class="input input-bordered w-full" required>
</div>
<div>
<label class="label">{{ __('Address') }}</label>
<input type="text" name="address"
wire:model.debounce.500ms="project.address"
class="input input-bordered w-full" required>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="label">{{ __('Latitude') }}</label>
<input type="number" step="any" name="lat"
wire:model.debounce.500ms="project.lat"
class="input input-bordered w-full" required>
</div>
<div>
<label class="label">{{ __('Longitude') }}</label>
<input type="number" step="any" name="lng"
wire:model.debounce.500ms="project.lng"
class="input input-bordered w-full" required>
</div>
</div>
<div>
<label class="label">{{ __('Status') }}</label>
<select name="status" wire:model="project.status"
class="select select-bordered w-full">
<option value="planning">{{ __('Planning') }}</option>
<option value="in_progress">{{ __('In progress') }}</option>
<option value="paused">{{ __('Paused') }}</option>
<option value="completed">{{ __('Completed') }}</option>
</select>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="label">{{ __('Start date') }}</label>
<input type="date" name="start_date"
wire:model.debounce.500ms="project.start_date"
class="input input-bordered w-full" required>
</div>
<div>
<label class="label">{{ __('Estimated end date') }}</label>
<input type="date" name="end_date_estimated"
wire:model.debounce.500ms="project.end_date_estimated"
class="input input-bordered w-full">
</div>
</div>
<button type="submit" class="btn btn-primary w-full">
{{ __('Update') }}
</button>
</form>
</div>
<!-- Phases Tab -->
<div id="tab-phases-{{ $project->id }}"
class="tab-content-base p-4 {{ $activeTab === 'phases' ? '' : 'hidden' }}">
<h2 class="text-xl font-bold mb-2">{{ __('Phases') }}</h2>
<livewire:phase-list :project="$project" />
</div>
<!-- Users Tab -->
<div id="tab-users-{{ $project->id }}"
class="tab-content-base p-4 {{ $activeTab === 'users' ? '' : 'hidden' }}">
<h2 class="text-xl font-bold mb-2">{{ __('Users') }}</h2>
<livewire:project-users :project="$project" />
</div>
</div>
</div>
{{-- Alpine.js for tab switching --}}
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('projectTabs', () => ({
activeTab: '{{ $activeTab }}',
projectId: {{ $project->id }},
setTab(tab) {
this.activeTab = tab;
// Update the Livewire component
this.$dispatch('tabChanged', {
tab: tab,
projectId: this.projectId
});
}
}));
});
</script>