feat: crowd types management UI with create/edit/deactivate
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,10 @@ final class CrowdTypeController extends Controller
|
||||
{
|
||||
Gate::authorize('viewAny', [CrowdType::class, $organisation]);
|
||||
|
||||
$crowdTypes = $organisation->crowdTypes()->where('is_active', true)->get();
|
||||
$crowdTypes = $organisation->crowdTypes()
|
||||
->orderByDesc('is_active')
|
||||
->orderBy('name')
|
||||
->get();
|
||||
|
||||
return CrowdTypeResource::collection($crowdTypes);
|
||||
}
|
||||
@@ -47,11 +50,7 @@ final class CrowdTypeController extends Controller
|
||||
{
|
||||
Gate::authorize('delete', [$crowdType, $organisation]);
|
||||
|
||||
if ($crowdType->persons()->exists()) {
|
||||
$crowdType->update(['is_active' => false]);
|
||||
} else {
|
||||
$crowdType->delete();
|
||||
}
|
||||
$crowdType->update(['is_active' => false]);
|
||||
|
||||
return response()->json(null, 204);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\Http\Requests\Api\V1;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
final class StoreCrowdTypeRequest extends FormRequest
|
||||
{
|
||||
@@ -17,7 +18,12 @@ final class StoreCrowdTypeRequest extends FormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => ['required', 'string', 'max:100'],
|
||||
'name' => [
|
||||
'required',
|
||||
'string',
|
||||
'max:100',
|
||||
Rule::unique('crowd_types')->where('organisation_id', $this->route('organisation')->id),
|
||||
],
|
||||
'system_type' => ['required', 'in:CREW,GUEST,ARTIST,VOLUNTEER,PRESS,PARTNER,SUPPLIER'],
|
||||
'color' => ['required', 'regex:/^#[0-9A-Fa-f]{6}$/'],
|
||||
'icon' => ['nullable', 'string', 'max:50'],
|
||||
|
||||
@@ -123,10 +123,11 @@ class CrowdTypeTest extends TestCase
|
||||
->assertJson(['data' => ['name' => 'New Name', 'color' => '#ff0000']]);
|
||||
}
|
||||
|
||||
public function test_destroy_deletes_crowd_type_without_persons(): void
|
||||
public function test_destroy_deactivates_crowd_type(): void
|
||||
{
|
||||
$crowdType = CrowdType::factory()->create([
|
||||
'organisation_id' => $this->organisation->id,
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
Sanctum::actingAs($this->orgAdmin);
|
||||
@@ -134,6 +135,47 @@ class CrowdTypeTest extends TestCase
|
||||
$response = $this->deleteJson("/api/v1/organisations/{$this->organisation->id}/crowd-types/{$crowdType->id}");
|
||||
|
||||
$response->assertNoContent();
|
||||
$this->assertDatabaseMissing('crowd_types', ['id' => $crowdType->id]);
|
||||
$this->assertDatabaseHas('crowd_types', [
|
||||
'id' => $crowdType->id,
|
||||
'is_active' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_store_duplicate_name_returns_422(): void
|
||||
{
|
||||
CrowdType::factory()->create([
|
||||
'organisation_id' => $this->organisation->id,
|
||||
'name' => 'Vrijwilliger',
|
||||
]);
|
||||
|
||||
Sanctum::actingAs($this->orgAdmin);
|
||||
|
||||
$response = $this->postJson("/api/v1/organisations/{$this->organisation->id}/crowd-types", [
|
||||
'name' => 'Vrijwilliger',
|
||||
'system_type' => 'VOLUNTEER',
|
||||
'color' => '#10b981',
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertJsonValidationErrors('name');
|
||||
}
|
||||
|
||||
public function test_index_includes_inactive_crowd_types(): void
|
||||
{
|
||||
CrowdType::factory()->create([
|
||||
'organisation_id' => $this->organisation->id,
|
||||
'is_active' => true,
|
||||
]);
|
||||
CrowdType::factory()->create([
|
||||
'organisation_id' => $this->organisation->id,
|
||||
'is_active' => false,
|
||||
]);
|
||||
|
||||
Sanctum::actingAs($this->orgAdmin);
|
||||
|
||||
$response = $this->getJson("/api/v1/organisations/{$this->organisation->id}/crowd-types");
|
||||
|
||||
$response->assertOk();
|
||||
$this->assertCount(2, $response->json('data'));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user