feat: add companies as top-level container for projects with departments

- Company → Project → (Locations + Departments) hierarchy
- Company CRUD (add, edit, delete) with AJAX
- Projects are created under a company via inline strip
- Two-column project body: Locations | Departments
- Stats show companies, projects, locations, departments, active projects
- Dynamic stat counters update on add/delete without page reload

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
ghassanandClaude Sonnet 4.6 committed 2026-05-26 18:05:04 +03:00
1 parent 60d57af630
commit a425e12349
6 files changed
+518 -264

No files matched your search

@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Settings;
use App\Http\Controllers\Controller;
use App\Models\Settings\Company;
use App\Models\Settings\Department;
use App\Models\Settings\Location;
use App\Models\Settings\ProjectSetting;
@@ -12,33 +13,60 @@ class ProjectSettingController extends Controller
{
public function index()
{
$projects = ProjectSetting::with([
'locations' => fn ($q) => $q->orderBy('name'),
'departments' => fn ($q) => $q->orderBy('name'),
$companies = Company::with([
'projects.locations' => fn ($q) => $q->orderBy('name'),
'projects.departments' => fn ($q) => $q->orderBy('name'),
])->orderBy('name')->get();
$allProjects = $companies->flatMap(fn ($c) => $c->projects);
$stats = [
'total_projects' => $projects->count(),
'active_projects' => $projects->where('is_active', true)->count(),
'total_locations' => $projects->sum(fn ($p) => $p->locations->count()),
'active_locations' => $projects->sum(fn ($p) => $p->locations->where('is_active', true)->count()),
'total_departments' => $projects->sum(fn ($p) => $p->departments->count()),
'total_companies' => $companies->count(),
'total_projects' => $allProjects->count(),
'active_projects' => $allProjects->where('is_active', true)->count(),
'total_locations' => $allProjects->sum(fn ($p) => $p->locations->count()),
'total_departments' => $allProjects->sum(fn ($p) => $p->departments->count()),
];
return view('settings.projects.index', compact('projects', 'stats'));
return view('settings.projects.index', compact('companies', 'stats'));
}
public function store(Request $request)
{
$validated = $request->validate(['name' => 'required|string|max:255|unique:settings_projects,name']);
$project = ProjectSetting::create(['name' => $validated['name'], 'is_active' => true]);
$validated = $request->validate([
'name' => 'required|string|max:255|unique:settings_projects,name',
'company_id' => 'required|exists:settings_companies,id',
]);
$project = ProjectSetting::create(['name' => $validated['name'], 'company_id' => $validated['company_id'], 'is_active' => true]);
return response()->json(['project' => [
'id' => $project->id,
'name' => $project->name,
'is_active' => $project->is_active,
'id' => $project->id,
'name' => $project->name,
'is_active' => $project->is_active,
'company_id' => $project->company_id,
]]);
}
// ── Company CRUD ──────────────────────────────────────────────────────────
public function storeCompany(Request $request)
{
$validated = $request->validate(['name' => 'required|string|max:255|unique:settings_companies,name']);
$company = Company::create(['name' => $validated['name'], 'is_active' => true]);
return response()->json(['company' => ['id' => $company->id, 'name' => $company->name, 'is_active' => $company->is_active]]);
}
public function updateCompany(Request $request, Company $company)
{
$validated = $request->validate(['name' => 'required|string|max:255|unique:settings_companies,name,' . $company->id]);
$company->update(['name' => $validated['name'], 'is_active' => $request->boolean('is_active', true)]);
return response()->json(['company' => ['id' => $company->id, 'name' => $company->name, 'is_active' => $company->is_active]]);
}
public function destroyCompany(Company $company)
{
$company->delete();
return response()->json(['ok' => true]);
}
public function update(Request $request, ProjectSetting $project)
{
$validated = $request->validate([