Create reusable Livewire component for project edit tabs and replace manual tabs implementation
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Livewire;
|
||||||
|
|
||||||
|
use Livewire\Component;
|
||||||
|
use App\Models\Project;
|
||||||
|
|
||||||
|
class ProjectEditTabs extends Component
|
||||||
|
{
|
||||||
|
public Project $project;
|
||||||
|
public string $activeTab = 'project-data';
|
||||||
|
|
||||||
|
public function mount(Project $project)
|
||||||
|
{
|
||||||
|
$this->project = $project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setActiveTab($tab)
|
||||||
|
{
|
||||||
|
$this->activeTab = $tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tabChanged($tab, $projectId)
|
||||||
|
{
|
||||||
|
if ($projectId == $this->project->id) {
|
||||||
|
$this->activeTab = $tab;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateProject()
|
||||||
|
{
|
||||||
|
$this->project->save();
|
||||||
|
|
||||||
|
session()->flash('message', __('Project updated successfully.'));
|
||||||
|
$this->dispatch('project-updated');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.project-edit-tabs');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
@@ -2,82 +2,6 @@
|
|||||||
<div class="max-w-2xl mx-auto p-4">
|
<div class="max-w-2xl mx-auto p-4">
|
||||||
<h1 class="text-2xl font-bold mb-4">{{ __('Edit Project') }}: {{ $project->name }}</h1>
|
<h1 class="text-2xl font-bold mb-4">{{ __('Edit Project') }}: {{ $project->name }}</h1>
|
||||||
|
|
||||||
<div class="tabs tab-box w-full">
|
<livewire:project-edit-tabs :project="$project" />
|
||||||
<div class="tab-toggle">
|
|
||||||
<input type="radio" name="tabs-project-edit" id="tab-project-data" checked class="tab-toggle" />
|
|
||||||
<label for="tab-project-data" class="tab tab-active">{{ __('Project Data') }}</label>
|
|
||||||
<input type="radio" name="tabs-project-edit" id="tab-phases" class="tab-toggle" />
|
|
||||||
<label for="tab-phases" class="tab">{{ __('Phases') }}</label>
|
|
||||||
<input type="radio" name="tabs-project-edit" id="tab-users" class="tab-toggle" />
|
|
||||||
<label for="tab-users" class="tab">{{ __('Users') }}</label>
|
|
||||||
</div>
|
|
||||||
<div class="tab-content">
|
|
||||||
<div id="tab-project-data" class="tab-content-base p-4">
|
|
||||||
<form action="{{ route('projects.update', $project) }}" method="POST" class="space-y-4">
|
|
||||||
@csrf
|
|
||||||
@method('PUT')
|
|
||||||
<div>
|
|
||||||
<label class="label">{{ __('Name') }}</label>
|
|
||||||
<input type="text" name="name" value="{{ old('name', $project->name) }}" class="input input-bordered w-full" required>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="label">{{ __('Address') }}</label>
|
|
||||||
<input type="text" name="address" value="{{ old('address', $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" value="{{ old('lat', $project->lat) }}" class="input input-bordered w-full" required>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="label">{{ ('Longitude') }}</label>
|
|
||||||
<input type="number" step="any" name="lng" value="{{ old('lng', $project->lng) }}" class="input input-bordered w-full" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="label">{{ __('Status') }}</label>
|
|
||||||
<select name="status" class="select select-bordered w-full">
|
|
||||||
<option value="planning" @selected($project->status == 'planning')>{{ __('Planning') }}</option>
|
|
||||||
<option value="in_progress" @selected($project->status == 'in_progress')>{{ __('In progress') }}</option>
|
|
||||||
<option value="paused" @selected($project->status == 'paused')>{{ __('Paused') }}</option>
|
|
||||||
<option value="completed" @selected($project->status == '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" value="{{ old('start_date', $project->start_date->format('Y-m-d')) }}" class="input input-bordered w-full" required>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="label">{{ ('Estimated end date') }}</label>
|
|
||||||
<input type="date" name="end_date_estimated" value="{{ old('end_date_estimated', $project->end_date_estimated?->format('Y-m-d')) }}" class="input input-bordered w-full">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary w-full">{{ __('Update') }}</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div id="tab-phases" class="tab-content-base p-4">
|
|
||||||
<h2 class="text-xl font-bold mb-2">{{ __('Phases') }}</h2>
|
|
||||||
<livewire:phase-list :project="$project" />
|
|
||||||
</div>
|
|
||||||
<div id="tab-users" class="tab-content-base p-4">
|
|
||||||
<h2 class="text-xl font-bold mb-2">{{ __('Users') }}</h2>
|
|
||||||
<livewire:project-users :project="$project" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const tabs = document.querySelectorAll('input[name="tabs-project-edit"]');
|
|
||||||
tabs.forEach(tab => {
|
|
||||||
tab.addEventListener('change', function() {
|
|
||||||
// Este evento se dispara cuando cambia el radio button seleccionado
|
|
||||||
// DaisyUI maneja automáticamente el mostrar/ocultar el contenido
|
|
||||||
// basado en los IDs que coinciden con los labels
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</div>
|
</div>
|
||||||
</x-app-layout>
|
</x-app-layout>
|
||||||
Reference in New Issue
Block a user