diff --git a/app/Group.php b/app/Group.php index 02774d8d..ef34327c 100644 --- a/app/Group.php +++ b/app/Group.php @@ -7,6 +7,7 @@ use App\Nami\HasNamiField; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\HasMany; class Group extends Model { @@ -28,6 +29,14 @@ class Group extends Model return $this->belongsTo(static::class, 'parent_id'); } + /** + * @return HasMany + */ + public function children(): HasMany + { + return $this->hasMany(static::class, 'parent_id'); + } + public static function booted(): void { static::creating(function (self $group) { diff --git a/app/Group/Actions/GroupApiIndexAction.php b/app/Group/Actions/GroupApiIndexAction.php new file mode 100644 index 00000000..95a03fd0 --- /dev/null +++ b/app/Group/Actions/GroupApiIndexAction.php @@ -0,0 +1,29 @@ + + */ + public function handle(): Collection + { + return Group::get(); + } + + public function asController(?Group $group = null): AnonymousResourceCollection + { + return GroupResource::collection($group ? $group->children()->withCount('children')->get() : Group::where('parent_id', null)->withCount('children')->get()); + } +} diff --git a/app/Group/Actions/GroupIndexAction.php b/app/Group/Actions/GroupIndexAction.php index accd6d40..7a474578 100644 --- a/app/Group/Actions/GroupIndexAction.php +++ b/app/Group/Actions/GroupIndexAction.php @@ -23,8 +23,11 @@ class GroupIndexAction public function asController(): Response { + session()->put('menu', 'group'); + session()->put('title', 'Gruppierungen'); + return Inertia::render('group/Index', [ - 'data' => GroupResource::collection($this->handle()), + 'data' => GroupResource::collection(Group::where('parent_id', null)->withCount('children')->get()), ]); } } diff --git a/app/Group/Resources/GroupResource.php b/app/Group/Resources/GroupResource.php index 9a126be1..1af818de 100644 --- a/app/Group/Resources/GroupResource.php +++ b/app/Group/Resources/GroupResource.php @@ -3,6 +3,7 @@ namespace App\Group\Resources; use App\Group; +use App\Group\Enums\Level; use App\Lib\HasMeta; use Illuminate\Http\Resources\Json\JsonResource; @@ -28,6 +29,10 @@ class GroupResource extends JsonResource 'parent_id' => $this->parent_id, 'id' => $this->id, 'level' => $this->level?->value, + 'children_count' => $this->children_count, + 'links' => [ + 'children' => route('api.group', ['group' => $this->id]), + ] ]; } @@ -39,7 +44,9 @@ class GroupResource extends JsonResource return [ 'links' => [ 'bulkstore' => route('group.bulkstore'), - ] + 'root_path' => route('api.group'), + ], + 'levels' => Level::forSelect(), ]; } } diff --git a/app/Membership/Actions/MassListAction.php b/app/Membership/Actions/MassListAction.php index a148ec20..36d809cd 100644 --- a/app/Membership/Actions/MassListAction.php +++ b/app/Membership/Actions/MassListAction.php @@ -18,7 +18,7 @@ class MassListAction session()->put('title', 'Mitgliedschaften zuweisen'); $activities = Activity::with('subactivities')->get(); - return Inertia::render('group/Index', [ + return Inertia::render('activity/Masslist', [ 'activities' => $activities->pluck('name', 'id'), 'subactivities' => $activities->mapWithKeys(fn (Activity $activity) => [$activity->id => $activity->subactivities()->pluck('name', 'id')]), 'groups' => Group::pluck('name', 'id'), diff --git a/resources/js/components/form/Text.vue b/resources/js/components/form/Text.vue index a0979470..24d6abeb 100644 --- a/resources/js/components/form/Text.vue +++ b/resources/js/components/form/Text.vue @@ -5,18 +5,8 @@  *
- +
@@ -242,25 +232,6 @@ var transformers = { }; export default { - data: function () { - return { - focus: false, - sizes: { - sm: { - wrap: 'field-wrap-sm', - field: 'size-sm', - }, - base: { - wrap: 'field-wrap-base', - field: 'size-base', - }, - lg: { - wrap: 'field-wrap-lg', - field: 'size-lg', - }, - }, - }; - }, props: { placeholder: { default: function () { @@ -312,23 +283,24 @@ export default { }, name: {}, }, - methods: { - onFocus() { - this.focus = true; - }, - onBlur() { - this.focus = false; - }, - onChange(v) { - if (this.mode !== 'none') { - this.transformedValue = v.target.value; - } - }, - onInput(v) { - if (this.mode === 'none') { - this.transformedValue = v.target.value; - } - }, + data: function () { + return { + focus: false, + sizes: { + sm: { + wrap: 'field-wrap-sm', + field: 'size-sm', + }, + base: { + wrap: 'field-wrap-base', + field: 'size-base', + }, + lg: { + wrap: 'field-wrap-lg', + field: 'size-lg', + }, + }, + }; }, computed: { transformedValue: { @@ -355,6 +327,25 @@ export default { this.$emit('input', this.default === undefined ? '' : this.default); } }, + methods: { + onFocus() { + this.focus = true; + }, + onBlur() { + this.focus = false; + }, + onChange(v) { + if (this.mode !== 'none') { + this.transformedValue = v.target.value; + } + }, + onInput(v) { + console.log(this.modelModifiers); + if (this.mode === 'none') { + this.transformedValue = v.target.value; + } + }, + }, }; diff --git a/resources/js/views/activity/Masslist.vue b/resources/js/views/activity/Masslist.vue new file mode 100644 index 00000000..ecbc9af9 --- /dev/null +++ b/resources/js/views/activity/Masslist.vue @@ -0,0 +1,94 @@ + + + diff --git a/resources/js/views/group/Index.vue b/resources/js/views/group/Index.vue index ecbc9af9..d3f3a073 100644 --- a/resources/js/views/group/Index.vue +++ b/resources/js/views/group/Index.vue @@ -1,94 +1,159 @@ - diff --git a/routes/web.php b/routes/web.php index 3f396df0..95bd5a56 100644 --- a/routes/web.php +++ b/routes/web.php @@ -19,6 +19,7 @@ use App\Invoice\Actions\InvoiceStoreAction; use App\Course\Actions\CourseUpdateAction; use App\Dashboard\Actions\IndexAction as DashboardIndexAction; use App\Efz\ShowEfzDocumentAction; +use App\Group\Actions\GroupApiIndexAction; use App\Group\Actions\GroupBulkstoreAction; use App\Group\Actions\GroupIndexAction; use App\Initialize\Actions\InitializeAction; @@ -129,6 +130,7 @@ Route::group(['middleware' => 'auth:web'], function (): void { // ----------------------------------- group ---------------------------------- Route::get('/group', GroupIndexAction::class)->name('group.index'); + Route::get('/api/group/{group?}', GroupApiIndexAction::class)->name('api.group'); Route::post('/group/bulkstore', GroupBulkstoreAction::class)->name('group.bulkstore'); // ----------------------------------- course ---------------------------------- diff --git a/tests/Feature/Group/IndexTest.php b/tests/Feature/Group/IndexTest.php index 25dcdac6..913ebdc1 100644 --- a/tests/Feature/Group/IndexTest.php +++ b/tests/Feature/Group/IndexTest.php @@ -11,27 +11,55 @@ class IndexTest extends TestCase { use DatabaseTransactions; - public function testItDisplaysAllActivitiesAndSubactivities(): void + public function testItDisplaysGroupPage(): void + { + $this->login()->loginNami()->withoutExceptionHandling(); + + $this->get('/group') + ->assertOk() + ->assertInertiaPath('data.meta.links.root_path', route('api.group')); + } + + public function testItDisplaysParentGroup(): void + { + $this->login()->loginNami()->withoutExceptionHandling(); + + $group = Group::factory()->create(['name' => 'Afff', 'inner_name' => 'Gruppe', 'level' => Level::REGION]); + + $this->get('/api/group') + ->assertJsonCount(2, 'data') + ->assertJsonPath('data.1.name', 'Afff') + ->assertJsonPath('data.1.inner_name', 'Gruppe') + ->assertJsonPath('data.1.id', $group->id) + ->assertJsonPath('data.1.level', 'Bezirk') + ->assertJsonPath('data.1.parent_id', null) + ->assertJsonPath('meta.links.bulkstore', route('group.bulkstore')); + } + + public function testItDisplaysGroupsForParent(): void { $this->login()->loginNami()->withoutExceptionHandling(); $group = Group::factory()->for(Group::first(), 'parent')->create(['name' => 'Afff', 'inner_name' => 'Gruppe', 'level' => Level::REGION]); + Group::factory()->for(Group::first(), 'parent')->create(['name' => 'Afff', 'inner_name' => 'Gruppe', 'level' => Level::REGION]); - $this->get('/group') - ->assertInertiaPath('data.data.1.name', 'Afff') - ->assertInertiaPath('data.data.1.inner_name', 'Gruppe') - ->assertInertiaPath('data.data.1.id', $group->id) - ->assertInertiaPath('data.data.1.level', 'Bezirk') - ->assertInertiaPath('data.data.1.parent_id', Group::first()->id) - ->assertInertiaPath('data.meta.links.bulkstore', route('group.bulkstore')); + $this->get('/api/group/' . Group::first()->id) + ->assertJsonCount(2, 'data') + ->assertJsonPath('data.0.name', 'Afff') + ->assertJsonPath('data.0.inner_name', 'Gruppe') + ->assertJsonPath('data.0.id', $group->id) + ->assertJsonPath('data.0.level', 'Bezirk') + ->assertJsonPath('data.0.parent_id', Group::first()->id) + ->assertJsonPath('data.0.links.children', route('api.group', ['group' => $group->id])) + ->assertJsonPath('meta.links.bulkstore', route('group.bulkstore')); } public function testLevelCanBeNull(): void { $this->login()->loginNami()->withoutExceptionHandling(); - Group::factory()->create(['level' => null]); + $group = Group::factory()->for(Group::first(), 'parent')->create(['level' => null]); - $this->get('/group')->assertInertiaPath('data.data.2.level', null); + $this->get('/api/group/' . Group::first()->id)->assertJsonPath('data.0.id', $group->id); } }