fix: restore Rappasoft tables + fix boot errors from security commit
- Restore UserTable/CompanyTable/ProjectTable usage in users, companies and projects-list pages (security commit had replaced them with plain HTML/DaisyUI tables, losing sorting/search/pagination/format) - Add missing User->company() belongsTo relationship (UserTable eager loads it; column + migration existed but relation was undefined) - Add #[Layout] attribute to CompanyManagement/ProjectList/PhaseProgress full-page Livewire components - Fix config/session.php: use env() instead of app()->environment() which fails during LoadConfiguration (env binding not yet registered) - Remove duplicate activeTab property in ProjectMap (fatal PHP error) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,12 +3,14 @@
|
|||||||
namespace App\Livewire;
|
namespace App\Livewire;
|
||||||
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
use Livewire\Attributes\Layout;
|
||||||
use Livewire\WithFileUploads;
|
use Livewire\WithFileUploads;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Http\Response;
|
use Illuminate\Http\Response;
|
||||||
|
|
||||||
|
#[Layout('layouts.app')]
|
||||||
class CompanyManagement extends Component
|
class CompanyManagement extends Component
|
||||||
{
|
{
|
||||||
use WithFileUploads;
|
use WithFileUploads;
|
||||||
@@ -236,6 +238,8 @@ class CompanyManagement extends Component
|
|||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return view('livewire.company-management');
|
return view('livewire.company-management', [
|
||||||
|
'companies' => $this->getCompaniesProperty(),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,9 +3,11 @@
|
|||||||
namespace App\Livewire;
|
namespace App\Livewire;
|
||||||
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
use Livewire\Attributes\Layout;
|
||||||
use App\Models\Phase;
|
use App\Models\Phase;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
#[Layout('layouts.app')]
|
||||||
class PhaseProgress extends Component
|
class PhaseProgress extends Component
|
||||||
{
|
{
|
||||||
public Phase $phase;
|
public Phase $phase;
|
||||||
|
|||||||
@@ -3,10 +3,12 @@
|
|||||||
namespace App\Livewire;
|
namespace App\Livewire;
|
||||||
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
use Livewire\Attributes\Layout;
|
||||||
use Livewire\WithPagination;
|
use Livewire\WithPagination;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
#[Layout('layouts.app')]
|
||||||
class ProjectList extends Component
|
class ProjectList extends Component
|
||||||
{
|
{
|
||||||
use WithPagination;
|
use WithPagination;
|
||||||
|
|||||||
@@ -42,9 +42,6 @@ class ProjectMap extends Component
|
|||||||
public $showFeatureImages = false;
|
public $showFeatureImages = false;
|
||||||
public $featureImageMarkers = [];
|
public $featureImageMarkers = [];
|
||||||
|
|
||||||
// Tab management
|
|
||||||
public $activeTab = 'edit'; // edit or list
|
|
||||||
|
|
||||||
public function mount(Project $project)
|
public function mount(Project $project)
|
||||||
{
|
{
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ class User extends Authenticatable
|
|||||||
'password' => 'hashed',
|
'password' => 'hashed',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
public function company()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Company::class);
|
||||||
|
}
|
||||||
|
|
||||||
// Many-to-many with projects
|
// Many-to-many with projects
|
||||||
public function projects()
|
public function projects()
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-2
@@ -169,8 +169,7 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Default to true in production; set SESSION_SECURE_COOKIE=false in local .env if needed
|
'secure' => env('SESSION_SECURE_COOKIE', env('APP_ENV', 'production') === 'production'),
|
||||||
'secure' => env('SESSION_SECURE_COOKIE', app()->environment('production')),
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<div class="py-12">
|
<div class="py-12">
|
||||||
<div class="max-w-5xl mx-auto sm:px-6 lg:px-8">
|
<div class="max-w-5xl mx-auto sm:px-6 lg:px-8">
|
||||||
<div class="bg-white rounded-lg shadow p-6">
|
<div class="bg-white rounded-lg shadow p-6">
|
||||||
@livewire('admin-users')
|
@livewire('user-table')
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,327 +1,21 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="mb-6">
|
|
||||||
<h2 class="text-2xl font-bold text-gray-800 flex items-center">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-blue-500 mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h10m-9-3h8m-7 0h7M8 13v2a2 2 0 002 2h5a2 2 0 002-2v-2m0 0V9a2 2 0 00-2-2H5a2 2 0 00-2 2v2Z" />
|
|
||||||
</svg>
|
|
||||||
{{ __('Company Management') }}
|
|
||||||
</h2>
|
|
||||||
<p class="text-gray-600 mt-2">{{ __('Manage the companies that participate in projects') }}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if(session('message'))
|
@if(session('message'))
|
||||||
<div class="mb-4 p-4 bg-green-50 border border-green-200 rounded-lg text-green-800">
|
<div class="alert alert-success mb-4">
|
||||||
|
<x-heroicon-o-check-circle class="w-5 h-5" />
|
||||||
{{ session('message') }}
|
{{ session('message') }}
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="space-y-6">
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<div>
|
||||||
<!-- Búsqueda y Botón de Nueva Empresa -->
|
<h2 class="text-2xl font-bold text-gray-800">{{ __('Company Management') }}</h2>
|
||||||
<div class="flex flex-col md:flex-row md:items-center md:justify-between">
|
<p class="text-sm text-gray-500 mt-1">{{ __('Manage the companies that participate in projects') }}</p>
|
||||||
<div class="w-full md:w-1/2">
|
|
||||||
<input type="text"
|
|
||||||
wire:model.live="search"
|
|
||||||
placeholder="{{ __('Search companies by name or tax ID...') }}"
|
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors">
|
|
||||||
</div>
|
|
||||||
<div class="w-full md:w-1/3 mt-4 md:mt-0">
|
|
||||||
<button wire:click="toggleCreateForm"
|
|
||||||
class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg flex items-center justify-center transition-colors">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
|
||||||
</svg>
|
|
||||||
{{ __('New Company') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Formulario de Creación/Edición -->
|
|
||||||
<div wire:ignore.self x-cloak>
|
|
||||||
<div x-show="@entangle('showCreateForm')" x-transition:enter="transition ease-out duration-100"
|
|
||||||
x-transition:enter-start="transform opacity-0 scale-95"
|
|
||||||
x-transition:enter-end="transform opacity-100 scale-100"
|
|
||||||
x-transition:leave="transition ease-in duration-75"
|
|
||||||
x-transition:leave-start="transform opacity-100 scale-100"
|
|
||||||
x-transition:leave-end="transform opacity-0 scale-95"
|
|
||||||
class="bg-white rounded-lg shadow-md p-6">
|
|
||||||
<div class="mb-4">
|
|
||||||
<h3 class="text-xl font-semibold text-gray-800 flex items-center">
|
|
||||||
{{ $editingCompanyId ? __('Edit Company') : __('New Company') }}
|
|
||||||
</h3>
|
|
||||||
<p class="text-gray-600 mt-1">
|
|
||||||
{{ __('Complete the company information. Fields marked with * are required.') }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if($errors->any())
|
|
||||||
<div class="mb-4 p-4 bg-red-50 border border-red-200 rounded-lg">
|
|
||||||
<strong>{{ __('Validation errors') }}:</strong>
|
|
||||||
<ul class="list-disc pl-5 mt-2 text-sm text-red-600">
|
|
||||||
@foreach($errors->all() as $error)
|
|
||||||
<li>{{ $error }}</li>
|
|
||||||
@endforeach
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
<form wire:submit.prevent="{{$editingCompanyId ? 'updateCompany' : 'createCompany'}}"
|
|
||||||
enctype="multipart/form-data"
|
|
||||||
class="space-y-4">
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('Name') }} *</label>
|
|
||||||
<input type="text"
|
|
||||||
wire:model="name"
|
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('Tax ID') }} *</label>
|
|
||||||
<input type="text"
|
|
||||||
wire:model="tax_id"
|
|
||||||
placeholder="{{ __('E.g.: B12345678') }}"
|
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('Nickname') }}</label>
|
|
||||||
<input type="text"
|
|
||||||
wire:model="apodo"
|
|
||||||
placeholder="{{ __('E.g.: Acme Construct') }}"
|
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('Status') }} *</label>
|
|
||||||
<select wire:model="estado"
|
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors">
|
|
||||||
<option value="">{{ __('Select a status') }}</option>
|
|
||||||
<option value="activo">{{ __('Active') }}</option>
|
|
||||||
<option value="inactivo">{{ __('Inactive') }}</option>
|
|
||||||
<option value="suspendido">{{ __('Suspended') }}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('Address') }}</label>
|
|
||||||
<textarea wire:model="address"
|
|
||||||
rows="3"
|
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors"></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('Company Type') }} *</label>
|
|
||||||
<select wire:model="type"
|
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors">
|
|
||||||
<option value="">{{ __('Select a type') }}</option>
|
|
||||||
<option value="owner">{{ __('Owner') }}</option>
|
|
||||||
<option value="constructor">{{ __('Constructor') }}</option>
|
|
||||||
<option value="subcontractor">{{ __('Subcontractor') }}</option>
|
|
||||||
<option value="consultant">{{ __('Consultant') }}</option>
|
|
||||||
<option value="supplier">{{ __('Supplier') }}</option>
|
|
||||||
<option value="other">{{ __('Other') }}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('Phone') }}</label>
|
|
||||||
<input type="tel"
|
|
||||||
wire:model="phone"
|
|
||||||
placeholder="+34 600 123 456"
|
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('Email') }}</label>
|
|
||||||
<input type="email"
|
|
||||||
wire:model="email"
|
|
||||||
placeholder="{{ __('contact@company.com') }}"
|
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('Website') }}</label>
|
|
||||||
<input type="url"
|
|
||||||
wire:model="website"
|
|
||||||
placeholder="https://www.company.com"
|
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('Company Logo') }}</label>
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<label class="cursor-pointer text-blue-600 hover:text-blue-800">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2 inline" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16v-2a2 2 0 012-2h2a2 2 0 012 2v2m-4 0h.01M12 12a2 2 0 100-4 2 2 0 000 4zm4.5-6.75a.75.75 0 100-1.5.75.75 0 000 1.5zm0 0h.01M7 10h.01M14 10h.01M10.363 5.636a.75.75 0 10-1.06-1.06l-.47 1.242A12.038 12.038 0 0112 9.042c1.373 0 2.702.28 3.901.784l1.242-.47a.75.75 0 10-1.06-1.06l-.469-1.241a9.038 9.038 0 00-2.342-.348z" />
|
|
||||||
</svg>
|
|
||||||
{{ __('Select file...') }}
|
|
||||||
</label>
|
|
||||||
<input type="file"
|
|
||||||
wire:model="logo"
|
|
||||||
accept="image/*"
|
|
||||||
class="mt-2 block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100">
|
|
||||||
@if($logo)
|
|
||||||
<div class="mt-3 flex items-center">
|
|
||||||
<img src="{{ $logo->temporaryUrl() }}"
|
|
||||||
alt="{{ __('Logo preview') }}"
|
|
||||||
class="h-12 w-12 object-contain border border-gray-200 rounded-lg">
|
|
||||||
<button type="button"
|
|
||||||
wire:click="logo = null"
|
|
||||||
class="ml-3 text-xs text-red-600 hover:text-red-800">
|
|
||||||
{{ __('Remove') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label class="block text-sm font-medium text-gray-700 mb-1">{{ __('Additional notes') }}</label>
|
|
||||||
<textarea wire:model="notes"
|
|
||||||
rows="4"
|
|
||||||
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-colors"></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center justify-end pt-4 space-x-3">
|
|
||||||
<button type="button"
|
|
||||||
wire:click="resetForm"
|
|
||||||
class="px-5 py-3 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 transition-colors">
|
|
||||||
{{ __('Cancel') }}
|
|
||||||
</button>
|
|
||||||
<button type="submit"
|
|
||||||
class="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-bold rounded-lg transition-colors">
|
|
||||||
{{ $editingCompanyId ? __('Update') : __('Create') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Lista de Empresas -->
|
|
||||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
|
||||||
<div class="px-6 py-4 border-b border-gray-200">
|
|
||||||
<h3 class="text-lg font-semibold text-gray-800 flex items-center">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2z" />
|
|
||||||
</svg>
|
|
||||||
{{ __('Company list') }} ({{ $companies->count() }})
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if($companies->isEmpty())
|
|
||||||
<div class="px-6 py-8 text-center text-gray-500">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="mx-auto h-12 w-12 text-gray-300 mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2z" />
|
|
||||||
</svg>
|
|
||||||
<p class="mt-2">{{ __('No companies registered. Create your first company using the button above.') }}</p>
|
|
||||||
</div>
|
|
||||||
@else
|
|
||||||
<div class="divide-y divide-gray-200">
|
|
||||||
@foreach($companies as $company)
|
|
||||||
<div class="px-6 py-4 flex flex-col md:flex-row md:items-start md:justify-between">
|
|
||||||
<div class="flex-1 md:w-1/2">
|
|
||||||
<div class="flex items-start space-x-3">
|
|
||||||
@if($company->logo_path && Storage::disk('public')->exists($company->logo_path))
|
|
||||||
<img src="{{ Storage::disk('public')->url($company->logo_path) }}"
|
|
||||||
alt="{{ __('Logo of') }} {{ $company->name }}"
|
|
||||||
class="h-12 w-12 object-contain border border-gray-200 rounded-lg flex-shrink-0">
|
|
||||||
@else
|
|
||||||
<div class="h-12 w-12 flex items-center justify-center bg-gray-100 rounded-lg text-gray-400 flex-shrink-0">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 2.25c-1.236 0-2.241.404-3.038 1.08a9.027 9.027 0 00-2.481 7.35c.178.404.317.845.418 1.306a4.42 4.42 0 001.266 2.05c.703.073 1.415.112 2.125.112a4.417 4.417 0 002.125-.112c.703 0 1.415-.039 2.125-.112a4.42 4.42 0 001.266-2.05a4.415 4.415 0 00.418-1.306c.797-.676 1.797-1.076 2.481-1.076A9.027 9.027 0 0018.978 9.68a11.025 11.025 0 01-4.597-.45z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
<div>
|
|
||||||
<h4 class="font-semibold text-gray-900">{{ $company->name }}</h4>
|
|
||||||
<p class="text-sm text-gray-600 truncate">
|
|
||||||
@if($company->tax_id)
|
|
||||||
{{ $company->tax_id }}
|
|
||||||
@else
|
|
||||||
{{ __('No tax ID') }}
|
|
||||||
@endif
|
|
||||||
</p>
|
|
||||||
@if($company->type)
|
|
||||||
<span class="inline-block mt-1 px-2 py-0.5 text-xs font-medium
|
|
||||||
@if($company->type === 'owner') bg-green-100 text-green-800
|
|
||||||
@elseif($company->type === 'constructor') bg-blue-100 text-blue-800
|
|
||||||
@elseif($company->type === 'subcontractor') bg-purple-100 text-purple-800
|
|
||||||
@elseif($company->type === 'consultant') bg-indigo-100 text-indigo-800
|
|
||||||
@elseif($company->type === 'supplier') bg-yellow-100 text-yellow-800
|
|
||||||
@else bg-gray-100 text-gray-800
|
|
||||||
endif
|
|
||||||
rounded">
|
|
||||||
{{ ucfirst($company->type) }}
|
|
||||||
</span>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-4 md:mt-0 md:w-1/2 text-right space-y-2">
|
|
||||||
<div class="text-sm text-gray-500 space-y-1">
|
|
||||||
@if($company->address)
|
|
||||||
<div class="flex items-start">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mt-0.5 text-gray-400 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.5 1.5 0 01-2.121-1.06L7 12.764l-.646.647a1 1 0 01-1.415-1.415l1.22-1.22a1.5 1.5 0 012.121-.39l3.707 3.707a1.5 1.5 0 011.06 2.12z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{ $company->address }}</span>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
@if($company->phone)
|
|
||||||
<div class="flex items-start">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mt-0.5 text-gray-400 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.8.52l1.68-1.4a1 1 0 01.82-.52h4a2 2 0 012 2v5.5a2 2 0 01-2 2H5a2 2 0 01-2-2V5z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{ $company->phone }}</span>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
@if($company->email)
|
|
||||||
<div class="flex items-start">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mt-0.5 text-gray-400 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12z" />
|
|
||||||
</svg>
|
|
||||||
<span>{{ $company->email }}</span>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex justify-end space-x-2">
|
|
||||||
<button wire:click="editCompany({{ $company->id }})"
|
|
||||||
class="text-sm text-blue-600 hover:text-blue-800 font-medium flex items-center">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
|
|
||||||
</svg>
|
|
||||||
{{ __('Edit') }}
|
|
||||||
</button>
|
|
||||||
<button wire:click="deleteCompany({{ $company->id }})"
|
|
||||||
class="text-sm text-red-600 hover:text-red-800 font-medium flex items-center"
|
|
||||||
wire:confirm="{{ __('Delete company confirmation') }}">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10h-3a2 2 0 00-2 2v2a2 2 0 002 2h3zm-3-4h1a2 2 0 012 2v2a2 2 0 01-2 2h-1V9a2 2 0 012-2z" />
|
|
||||||
</svg>
|
|
||||||
{{ __('Delete') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@if(!$loop->last)
|
|
||||||
<div class="border-t border-gray-200"></div>
|
|
||||||
@endforeach
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
</div>
|
</div>
|
||||||
|
<a href="{{ route('companies.create') }}" class="btn btn-primary btn-sm gap-1" wire:navigate>
|
||||||
|
<x-heroicon-o-plus class="w-4 h-4" />
|
||||||
|
{{ __('New Company') }}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<livewire:company-table />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,51 +1,3 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between mb-4">
|
<livewire:project-table />
|
||||||
<input type="text" wire:model.live="search" placeholder="{{ __('Search') }}..." class="input input-bordered w-64" />
|
|
||||||
<select wire:model.live="statusFilter" class="select select-bordered">
|
|
||||||
<option value="">{{ __('All') }}</option>
|
|
||||||
<option value="planning">{{ __('Planning') }}</option>
|
|
||||||
<option value="in_progress">{{ __('In progress') }}</option>
|
|
||||||
<option value="paused">{{ __('Paused') }}</option>
|
|
||||||
<option value="completed">{{ __('Completed') }}</option>
|
|
||||||
</select>
|
|
||||||
@can('create projects')
|
|
||||||
<a href="{{ route('projects.create') }}" class="btn btn-primary">+ {{ __('New Project') }}</a>
|
|
||||||
@endcan
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="overflow-x-auto">
|
|
||||||
<table class="table table-zebra">
|
|
||||||
<thead>
|
|
||||||
<tr><th>{{ __('Name') }}</th><th>{{ __('Address') }}</th><th>{{ __('Status') }}</th><th>{{ __('Progress') }}</th><th>{{ __('Actions') }}</th></tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach($projects as $project)
|
|
||||||
<tr>
|
|
||||||
<td>{{ $project->name }}</td>
|
|
||||||
<td>{{ $project->address }}</td>
|
|
||||||
<td>{{ __(ucfirst(str_replace('_', ' ', $project->status))) }}</td>
|
|
||||||
<td>
|
|
||||||
<div class="w-full bg-gray-200 rounded-full h-2.5">
|
|
||||||
<div class="bg-primary h-2.5 rounded-full" style="width: {{ $project->phases->avg('progress_percent') }}%"></div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a href="{{ route('projects.dashboard', $project) }}" class="btn btn-sm btn-outline gap-1">
|
|
||||||
<x-heroicon-o-squares-2x2 class="w-3.5 h-3.5" />
|
|
||||||
Dashboard
|
|
||||||
</a>
|
|
||||||
<a href="{{ route('projects.map', $project) }}" class="btn btn-sm btn-outline gap-1">
|
|
||||||
<x-heroicon-o-map class="w-3.5 h-3.5" />
|
|
||||||
{{ __('Map') }}
|
|
||||||
</a>
|
|
||||||
@can('edit projects')
|
|
||||||
<a href="{{ route('projects.edit', $project) }}" class="btn btn-sm btn-warning">{{ __('Edit') }}</a>
|
|
||||||
@endcan
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{{ $projects->links() }}
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user