feat: i18n, language switcher fix, DataTable improvements, blade translations
- Translation system: lang/es/ PHP files (auth, validation, pagination, passwords)
- Rappasoft vendor translations published (lang/vendor/livewire-tables/es/)
- JSON files synced to 391 keys (EN + ES, full parity)
- APP_LOCALE changed to 'es', users.locale column default changed to 'es'
- Language switcher fixed: JS event + window.location.reload() avoids /livewire/update redirect
- SetLocale middleware fallback uses config('app.locale') instead of hardcoded 'en'
- setSortingPillsEnabled(false) on ProjectTable, CompanyTable, UserTable
- Translated 17 blade views: project-map, template-manager, layer-manager,
company-management, phase-list, media-manager, reports-dashboard,
client-projects, layer-upload, project-form, project-map-editor-tab,
admin/users, projects/media, projects/templates, layouts/client
- Navigation 'Empresas' link uses __('Companies')
- Fixed typo key 'Fases and layers' -> 'Phases and layers'
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,9 +4,8 @@ namespace App\Livewire;
|
||||
|
||||
use Rappasoft\LaravelLivewireTables\DataTableComponent;
|
||||
use Rappasoft\LaravelLivewireTables\Views\Column;
|
||||
use Rappasoft\LaravelLivewireTables\Views\Columns\{BooleanColumn, ButtonGroupColumn, LinkColumn, ImageColumn};
|
||||
use Rappasoft\LaravelLivewireTables\Views\Filters\{DateFilter, MultiSelectFilter, SelectFilter};
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Models\Project;
|
||||
|
||||
class ProjectTable extends DataTableComponent
|
||||
@@ -17,86 +16,102 @@ class ProjectTable extends DataTableComponent
|
||||
{
|
||||
$this->setPrimaryKey('id')
|
||||
->setDefaultSort('created_at', 'desc')
|
||||
->setTableAttributes(['class' => 'table-auto w-full']);
|
||||
->setSortingPillsEnabled(false)
|
||||
->setAdditionalSelects(['projects.id as id', 'projects.created_at as created_at']);
|
||||
}
|
||||
|
||||
$this->setThAttributes(function(Column $column) {
|
||||
return ['class' => 'px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider'];
|
||||
});
|
||||
|
||||
$this->setTdAttributes(function(Column $column) {
|
||||
return ['class' => 'px-4 py-2 whitespace-nowrap text-sm text-gray-900'];
|
||||
});
|
||||
public function builder(): Builder
|
||||
{
|
||||
return Project::accessibleBy(Auth::user())
|
||||
->with('phases');
|
||||
}
|
||||
|
||||
public function columns(): array
|
||||
{
|
||||
return [
|
||||
Column::make(__('ID'), 'id')
|
||||
Column::make('Referencia', 'reference')
|
||||
->sortable()
|
||||
->searchable()
|
||||
->format(function ($value, $row) {
|
||||
$url = route('projects.dashboard', $row->id);
|
||||
return $value
|
||||
? '<a href="'.$url.'" class="font-mono text-xs text-primary hover:underline" wire:navigate>'.e($value).'</a>'
|
||||
: '<span class="text-gray-300">—</span>';
|
||||
})
|
||||
->html(),
|
||||
|
||||
Column::make(__('Name'), 'name')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
Column::make(__('Project Name'), 'name')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
|
||||
Column::make(__('Address'), 'address')
|
||||
->sortable()
|
||||
->searchable(),
|
||||
->searchable()
|
||||
->format(fn ($value) => $value
|
||||
? '<span class="truncate block max-w-xs" title="'.e($value).'">'.e($value).'</span>'
|
||||
: '<span class="text-gray-400">—</span>')
|
||||
->html(),
|
||||
|
||||
Column::make(__('Status'), 'status')
|
||||
->sortable(),
|
||||
->sortable()
|
||||
->format(function ($value) {
|
||||
$map = [
|
||||
'planning' => ['badge-ghost', 'Planificación'],
|
||||
'in_progress' => ['badge-primary', 'En progreso'],
|
||||
'paused' => ['badge-warning', 'Pausado'],
|
||||
'completed' => ['badge-success', 'Completado'],
|
||||
];
|
||||
[$cls, $label] = $map[$value] ?? ['badge-ghost', ucfirst($value)];
|
||||
return '<span class="badge '.$cls.'">'.$label.'</span>';
|
||||
})
|
||||
->html(),
|
||||
|
||||
Column::make(__('Progress'))
|
||||
->label(function ($row) {
|
||||
$avg = $row->phases->avg('progress_percent') ?? 0;
|
||||
$pct = round($avg);
|
||||
return '
|
||||
<div class="flex items-center gap-2 min-w-[100px]">
|
||||
<div class="flex-1 bg-gray-200 rounded-full h-2">
|
||||
<div class="bg-primary h-2 rounded-full" style="width:'.$pct.'%"></div>
|
||||
</div>
|
||||
<span class="text-xs text-gray-500 w-8 text-right">'.$pct.'%</span>
|
||||
</div>';
|
||||
})
|
||||
->html(),
|
||||
|
||||
Column::make(__('Start Date'), 'start_date')
|
||||
->sortable()
|
||||
->format(fn ($value, $row, $column) => $value ? $value->format('Y-m-d') : ''),
|
||||
->format(fn ($value) => $value ? $value->format('d/m/Y') : '—'),
|
||||
|
||||
Column::make(__('Estimated End Date'), 'end_date_estimated')
|
||||
Column::make(__('Est. End'), 'end_date_estimated')
|
||||
->sortable()
|
||||
->format(fn ($value, $row, $column) => $value ? $value->format('Y-m-d') : ''),
|
||||
->format(fn ($value) => $value ? $value->format('d/m/Y') : '—'),
|
||||
|
||||
Column::make(__('Actions'))
|
||||
->label(function ($row) {
|
||||
$confirm = __('Are you sure you want to delete this project?');
|
||||
|
||||
return '
|
||||
<div class="flex space-x-2">
|
||||
<a href="'.route('projects.edit', $row->id).'" class="btn btn-sm">'.__('Edit').'</a>
|
||||
<form action="'.route('projects.destroy', $row->id).'" method="POST" onsubmit="return confirm(\''.$confirm.'\');">
|
||||
'.csrf_field().'
|
||||
<input type="hidden" name="_method" value="DELETE">
|
||||
<button type="submit" class="btn btn-sm">'.__('Delete').'</button>
|
||||
</form>
|
||||
</div>';
|
||||
})
|
||||
->html(),
|
||||
->label(function ($row) {
|
||||
$dashboard = route('projects.dashboard', $row->id);
|
||||
$map = route('projects.map', $row->id);
|
||||
$edit = route('projects.edit', $row->id);
|
||||
|
||||
ButtonGroupColumn::make(__('Actions'))
|
||||
->attributes(function($row) {
|
||||
return [
|
||||
'class' => 'space-x-2',
|
||||
];
|
||||
})
|
||||
->buttons([
|
||||
LinkColumn::make('Edit')
|
||||
->title(fn($row) => __('Edit'))
|
||||
->location(fn($row) => route('projects.edit', $row->id))
|
||||
->attributes(function($row) {
|
||||
return [
|
||||
'target' => '_blank',
|
||||
'class' => 'text-blue-500 hover:underline',
|
||||
];
|
||||
}),
|
||||
$canEdit = Auth::user()->can('edit projects');
|
||||
|
||||
LinkColumn::make('View') // make() has no effect in this case but needs to be set anyway
|
||||
->title(fn($row) => __('View'))
|
||||
->location(fn($row) => route('projects.map', $row->id))
|
||||
->attributes(function($row) {
|
||||
return [
|
||||
'class' => 'text-blue-500 hover:underline',
|
||||
];
|
||||
}),
|
||||
|
||||
]),
|
||||
$html = '<div class="flex items-center gap-1">';
|
||||
$html .= '<a href="'.$dashboard.'" class="btn btn-xs btn-outline" title="Dashboard" wire:navigate>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zm10 0a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"/></svg>
|
||||
</a>';
|
||||
$html .= '<a href="'.$map.'" class="btn btn-xs btn-outline" title="Mapa" wire:navigate>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7"/></svg>
|
||||
</a>';
|
||||
if ($canEdit) {
|
||||
$html .= '<a href="'.$edit.'" class="btn btn-xs btn-warning" title="Editar" wire:navigate>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/></svg>
|
||||
</a>';
|
||||
}
|
||||
$html .= '</div>';
|
||||
return $html;
|
||||
})
|
||||
->html(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -104,4 +119,4 @@ class ProjectTable extends DataTableComponent
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user