diff --git a/CLAUDE.md b/CLAUDE.md
index d20edf7..87107c6 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -360,3 +360,12 @@ To trigger a toast from JavaScript (e.g. after an in-page action), call:
showToast('Message text', 'success'); // types: success | error | info | warn
```
**Never** add inline `@if(session('success'))` banner divs to individual views — the layout handles all of them. The toast appears bottom-right, auto-dismisses after 4 s, has a shrinking progress bar, and can be clicked or ×-closed early.
+
+### 10. Purchase Request creation — always use ``
+The create form lives in `resources/views/components/purchase/request-modal.blade.php` as a reusable Blade component. Wherever a "New Purchase Request" trigger is needed, drop in the component tag — it renders the button and the full modal itself:
+```blade
+
+```
+- **Never** link to `route('purchase.requests.create')` for creating new requests — the component replaces that flow entirely.
+- The component is self-contained: it owns the trigger button, the Alpine.js open/close state, the full MPR form (POSTing to `purchase.requests.store`), dynamic item rows, and validation-error auto-reopen logic.
+- The `/purchase/requests/create` page and route remain as a fallback but should not be referenced in new UI.
diff --git a/app/Http/Controllers/Settings/ProjectSettingController.php b/app/Http/Controllers/Settings/ProjectSettingController.php
index 2e2f2cc..131aa0b 100644
--- a/app/Http/Controllers/Settings/ProjectSettingController.php
+++ b/app/Http/Controllers/Settings/ProjectSettingController.php
@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Settings;
use App\Http\Controllers\Controller;
+use App\Models\Settings\Location;
use App\Models\Settings\ProjectSetting;
use Illuminate\Http\Request;
@@ -10,7 +11,7 @@ class ProjectSettingController extends Controller
{
public function index()
{
- $projects = ProjectSetting::orderBy('name')->get();
+ $projects = ProjectSetting::with('locations')->orderBy('name')->get();
return view('settings.projects.index', compact('projects'));
}
@@ -36,4 +37,27 @@ class ProjectSettingController extends Controller
$project->delete();
return redirect()->route('settings.projects.index')->with('success', 'Project deleted.');
}
+
+ public function storeLocation(Request $request, ProjectSetting $project)
+ {
+ $request->validate(['name' => 'required|string|max:255']);
+ $project->locations()->create(['name' => $request->name, 'is_active' => true]);
+ return redirect()->route('settings.projects.index')->with('success', 'Location added.');
+ }
+
+ public function updateLocation(Request $request, ProjectSetting $project, Location $location)
+ {
+ $request->validate(['name' => 'required|string|max:255']);
+ $location->update([
+ 'name' => $request->name,
+ 'is_active' => $request->boolean('is_active', true),
+ ]);
+ return redirect()->route('settings.projects.index')->with('success', 'Location updated.');
+ }
+
+ public function destroyLocation(ProjectSetting $project, Location $location)
+ {
+ $location->delete();
+ return redirect()->route('settings.projects.index')->with('success', 'Location deleted.');
+ }
}
diff --git a/app/Models/Settings/Location.php b/app/Models/Settings/Location.php
index 9bc36ea..25778bf 100644
--- a/app/Models/Settings/Location.php
+++ b/app/Models/Settings/Location.php
@@ -8,7 +8,7 @@ class Location extends Model
{
protected $table = 'settings_locations';
- protected $fillable = ['name', 'is_active'];
+ protected $fillable = ['name', 'project_id', 'is_active'];
protected $casts = ['is_active' => 'boolean'];
@@ -16,4 +16,9 @@ class Location extends Model
{
return $query->where('is_active', true);
}
+
+ public function project(): \Illuminate\Database\Eloquent\Relations\BelongsTo
+ {
+ return $this->belongsTo(\App\Models\Settings\ProjectSetting::class, 'project_id');
+ }
}
diff --git a/app/Models/Settings/ProjectSetting.php b/app/Models/Settings/ProjectSetting.php
index 8ff645d..070bc70 100644
--- a/app/Models/Settings/ProjectSetting.php
+++ b/app/Models/Settings/ProjectSetting.php
@@ -16,4 +16,9 @@ class ProjectSetting extends Model
{
return $query->where('is_active', true);
}
+
+ public function locations(): \Illuminate\Database\Eloquent\Relations\HasMany
+ {
+ return $this->hasMany(\App\Models\Settings\Location::class, 'project_id');
+ }
}
diff --git a/database/migrations/2026_05_25_000000_add_project_id_to_settings_locations_table.php b/database/migrations/2026_05_25_000000_add_project_id_to_settings_locations_table.php
new file mode 100644
index 0000000..2c9abde
--- /dev/null
+++ b/database/migrations/2026_05_25_000000_add_project_id_to_settings_locations_table.php
@@ -0,0 +1,30 @@
+foreignId('project_id')
+ ->nullable()
+ ->after('name')
+ ->constrained('settings_projects')
+ ->nullOnDelete();
+
+ $table->index('project_id');
+ });
+ }
+
+ public function down(): void
+ {
+ Schema::table('settings_locations', function (Blueprint $table) {
+ $table->dropIndex(['project_id']);
+ $table->dropForeign(['project_id']);
+ $table->dropColumn('project_id');
+ });
+ }
+};
diff --git a/resources/views/components/purchase/request-modal.blade.php b/resources/views/components/purchase/request-modal.blade.php
new file mode 100644
index 0000000..fb04d40
--- /dev/null
+++ b/resources/views/components/purchase/request-modal.blade.php
@@ -0,0 +1,276 @@
+@php
+$hasErrors = $errors->any();
+$mprProjects = \App\Models\Settings\ProjectSetting::active()->with(['locations' => function($q){ $q->where('is_active', true)->orderBy('name'); }])->orderBy('name')->get();
+@endphp
+
+{{-- Trigger button --}}
+
+
+{{-- ── Modal overlay ── --}}
+
+
+
+
+ {{-- ── Header ── --}}
+
+
+
+
+
New Purchase Request
+
Material Purchase Request (MPR)
+
+
+
+
+
+ {{-- ── Scrollable body ── --}}
+
+
+ @if($errors->any())
+
+
Please fix the following:
+
+ @foreach($errors->all() as $error)
+ - {{ $error }}
+ @endforeach
+
+
+ @endif
+
+
+
+
+ {{-- ── Footer ── --}}
+
+
+
+
+
+
+
+
+
diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php
index 8e6ba63..362755b 100644
--- a/resources/views/layouts/app.blade.php
+++ b/resources/views/layouts/app.blade.php
@@ -175,11 +175,22 @@
System
+
+
+ Projects
+