diff --git a/app/Activity.php b/app/Activity.php index b0dd3703..f469bb10 100644 --- a/app/Activity.php +++ b/app/Activity.php @@ -2,13 +2,15 @@ namespace App; +use App\Nami\HasNamiField; use Illuminate\Database\Eloquent\Model; -use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\BelongsToMany; class Activity extends Model { + use HasNamiField; + public $fillable = ['name', 'nami_id']; public $timestamps = false; @@ -20,7 +22,4 @@ class Activity extends Model return $this->belongsToMany(Subactivity::class); } - public static function nami(int $id): ?self { - return static::firstWhere('nami_id', $id); - } } diff --git a/app/Http/Views/MemberView.php b/app/Http/Views/MemberView.php index ac4817e0..bc4be28a 100644 --- a/app/Http/Views/MemberView.php +++ b/app/Http/Views/MemberView.php @@ -13,7 +13,13 @@ use Illuminate\Http\Request; class MemberView { public function index(Request $request, array $filter) { return [ - 'data' => MemberResource::collection(Member::select('*')->filter($filter)->search($request->query('search', null))->with('billKind')->with('payments')->withSubscriptionName()->withIsConfirmed()->withPendingPayment()->orderByRaw('lastname, firstname')->paginate(15)), + 'data' => MemberResource::collection(Member::select('*') + ->filter($filter)->search($request->query('search', null)) + ->with('billKind')->with('payments') + ->withSubscriptionName()->withIsConfirmed()->withPendingPayment()->withAgeGroup() + ->orderByRaw('lastname, firstname') + ->paginate(15) + ), 'toolbar' => [ ['href' => route('member.index'), 'label' => 'Zurück', 'color' => 'primary', 'icon' => 'plus'] ], 'paymentDefaults' => ['nr' => date('Y')], 'subscriptions' => Subscription::get()->pluck('name', 'id'), diff --git a/app/Member/Member.php b/app/Member/Member.php index 16d48da0..eac57b19 100644 --- a/app/Member/Member.php +++ b/app/Member/Member.php @@ -160,6 +160,16 @@ class Member extends Model ]); } + public function scopeWithAgeGroup(Builder $q): Builder { + return $q->addSelect([ + 'age_group_icon' => Subactivity::select('slug') + ->join('memberships', 'memberships.subactivity_id', 'subactivities.id') + ->where('subactivities.is_age_group', true) + ->whereColumn('memberships.member_id', 'members.id') + ->limit(1) + ]); + } + public function scopeWhereHasPendingPayment(Builder $q): Builder { return $q->whereHas('payments', function(Builder $q): void { $q->whereNeedsPayment(); diff --git a/app/Member/MemberResource.php b/app/Member/MemberResource.php index 64255015..36ab2cd9 100644 --- a/app/Member/MemberResource.php +++ b/app/Member/MemberResource.php @@ -52,6 +52,7 @@ class MemberResource extends JsonResource 'pending_payment' => $this->pending_payment ? number_format($this->pending_payment / 100, 2, ',', '.').' €' : null, 'first_activity_id' => $this->first_activity_id, 'first_subactivity_id' => $this->first_subactivity_id, + 'age_group_icon' => $this->age_group_icon, ]; } } diff --git a/app/Member/Membership.php b/app/Member/Membership.php index 7ffb598e..339667dd 100644 --- a/app/Member/Membership.php +++ b/app/Member/Membership.php @@ -9,5 +9,5 @@ class Membership extends Model { use HasFactory; - public $fillable = ['activity_id', 'group_id', 'member_id', 'nami_id', 'created_at']; + public $fillable = ['subactivity_id', 'activity_id', 'group_id', 'member_id', 'nami_id', 'created_at']; } diff --git a/app/Nami/HasNamiField.php b/app/Nami/HasNamiField.php new file mode 100644 index 00000000..7a1c79ce --- /dev/null +++ b/app/Nami/HasNamiField.php @@ -0,0 +1,21 @@ + 'boolean', + ]; + + public function sluggable(): array + { + return [ + 'slug' => [ + 'source' => 'name', + ], + ]; + } + + public function activities(): BelongsToMany + { return $this->belongsToMany(Activity::class); } + } diff --git a/composer.json b/composer.json index bf7023b9..a1bccfca 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,7 @@ "require": { "php": "^7.2.5", "aweos/agnoster-installer": "1.0", + "cviebrock/eloquent-sluggable": "^8.0", "doctrine/dbal": "^3.1", "fideloper/proxy": "^4.2", "fruitcake/laravel-cors": "^1.0", diff --git a/composer.lock b/composer.lock index 86ca0e5a..1db14515 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "308f33b72c09fca3d6d3153bfb3cab1e", + "content-hash": "edaca62d8f09ce92797f46e31f41b45a", "packages": [ { "name": "asm89/stack-cors", @@ -147,6 +147,80 @@ ], "time": "2021-01-20T22:51:39+00:00" }, + { + "name": "cocur/slugify", + "version": "v4.0.0", + "source": { + "type": "git", + "url": "https://github.com/cocur/slugify.git", + "reference": "3f1ffc300f164f23abe8b64ffb3f92d35cec8307" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cocur/slugify/zipball/3f1ffc300f164f23abe8b64ffb3f92d35cec8307", + "reference": "3f1ffc300f164f23abe8b64ffb3f92d35cec8307", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=7.0" + }, + "conflict": { + "symfony/config": "<3.4 || >=4,<4.3", + "symfony/dependency-injection": "<3.4 || >=4,<4.3", + "symfony/http-kernel": "<3.4 || >=4,<4.3", + "twig/twig": "<2.12.1" + }, + "require-dev": { + "laravel/framework": "~5.1", + "latte/latte": "~2.2", + "league/container": "^2.2.0", + "mikey179/vfsstream": "~1.6.8", + "mockery/mockery": "^1.3", + "nette/di": "~2.4", + "phpunit/phpunit": "^5.7.27", + "pimple/pimple": "~1.1", + "plumphp/plum": "~0.1", + "symfony/config": "^3.4 || ^4.3 || ^5.0", + "symfony/dependency-injection": "^3.4 || ^4.3 || ^5.0", + "symfony/http-kernel": "^3.4 || ^4.3 || ^5.0", + "twig/twig": "^2.12.1 || ~3.0", + "zendframework/zend-modulemanager": "~2.2", + "zendframework/zend-servicemanager": "~2.2", + "zendframework/zend-view": "~2.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Cocur\\Slugify\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Florian Eckerstorfer", + "email": "florian@eckerstorfer.co", + "homepage": "https://florian.ec" + }, + { + "name": "Ivo Bathke", + "email": "ivo.bathke@gmail.com" + } + ], + "description": "Converts a string into a slug.", + "keywords": [ + "slug", + "slugify" + ], + "support": { + "issues": "https://github.com/cocur/slugify/issues", + "source": "https://github.com/cocur/slugify/tree/master" + }, + "time": "2019-12-14T13:04:14+00:00" + }, { "name": "composer/package-versions-deprecated", "version": "1.11.99.2", @@ -220,6 +294,79 @@ ], "time": "2021-05-24T07:46:03+00:00" }, + { + "name": "cviebrock/eloquent-sluggable", + "version": "8.0.8", + "source": { + "type": "git", + "url": "https://github.com/cviebrock/eloquent-sluggable.git", + "reference": "16e21db24d80180f870c3c7c4faf3d3af23f4117" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cviebrock/eloquent-sluggable/zipball/16e21db24d80180f870c3c7c4faf3d3af23f4117", + "reference": "16e21db24d80180f870c3c7c4faf3d3af23f4117", + "shasum": "" + }, + "require": { + "cocur/slugify": "^4.0", + "illuminate/config": "^8.0", + "illuminate/database": "^8.0", + "illuminate/support": "^8.0", + "php": "^7.3|^8.0" + }, + "require-dev": { + "limedeck/phpunit-detailed-printer": "^6.0", + "mockery/mockery": "^1.4.2", + "orchestra/database": "^6.0", + "orchestra/testbench": "^6.0", + "phpunit/phpunit": "^9.4" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Cviebrock\\EloquentSluggable\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Cviebrock\\EloquentSluggable\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Colin Viebrock", + "email": "colin@viebrock.ca" + } + ], + "description": "Easy creation of slugs for your Eloquent models in Laravel", + "homepage": "https://github.com/cviebrock/eloquent-sluggable", + "keywords": [ + "eloquent", + "eloquent-sluggable", + "laravel", + "lumen", + "slug", + "sluggable" + ], + "support": { + "issues": "https://github.com/cviebrock/eloquent-sluggable/issues", + "source": "https://github.com/cviebrock/eloquent-sluggable/tree/8.0.8" + }, + "funding": [ + { + "url": "https://github.com/cviebrock", + "type": "github" + } + ], + "time": "2021-06-12T01:05:33+00:00" + }, { "name": "doctrine/cache", "version": "2.0.3", diff --git a/database/migrations/2021_08_22_151457_create_memberships_subactivity_id_column.php b/database/migrations/2021_08_22_151457_create_memberships_subactivity_id_column.php new file mode 100644 index 00000000..0cfceb05 --- /dev/null +++ b/database/migrations/2021_08_22_151457_create_memberships_subactivity_id_column.php @@ -0,0 +1,59 @@ +foreignId('subactivity_id')->nullable()->constrained(); + $table->unsignedBigInteger('activity_id')->change(); + $table->foreign('activity_id')->references('id')->on('activities'); + }); + + Member::whereNotNull('nami_id')->get()->each(function($member): void { + collect($member->getNamiMemberships(Nami::login(env('NAMI_ADMIN_USER'), env('NAMI_ADMIN_PW'))))->filter( + fn ($membership): bool => dump($membership) && $membership['ends_at'] === null, + )->each(function($membership) use ($member): void { + if ($member->memberships()->where('nami_id', $membership['id'])->exists()) { + return; + } + + $member->memberships()->create([ + 'nami_id' => $membership['id'], + 'activity_id' => Activity::nami($membership['activity_id'])->id, + 'subactivity_id' => $membership['subactivity_id'] + ? Subactivity::nami($membership['subactivity_id'])->id + : null, + 'group_id' => Group::nami($membership['group_id'])->id, + 'created_at' => $membership['starts_at'], + ]); + }); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('memberships', function (Blueprint $table) { + // + }); + } +} diff --git a/database/migrations/2021_08_22_165326_create_activities_slug_column.php b/database/migrations/2021_08_22_165326_create_activities_slug_column.php new file mode 100644 index 00000000..814c1541 --- /dev/null +++ b/database/migrations/2021_08_22_165326_create_activities_slug_column.php @@ -0,0 +1,36 @@ +boolean('is_age_group')->default(false)->after('name'); + $table->string('slug')->after('name'); + }); + Subactivity::get()->each(fn ($subactivity) => $subactivity->update([])); + Subactivity::whereIn('nami_id', [1,2,3,4,49])->get()->each(fn ($subactivity) => $subactivity->update(['is_age_group' => true])); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('activities', function (Blueprint $table) { + $table->dropColumn('slug'); + }); + } +} diff --git a/resources/css/table.css b/resources/css/table.css index d3038a9a..518bb1bd 100644 --- a/resources/css/table.css +++ b/resources/css/table.css @@ -1,33 +1,32 @@ .custom-table { - display: table; width: 100%; - & > header > div { - @apply px-6 text-gray-200 font-semibold py-3 border-gray-600 border-b; + & > thead > th { + @apply text-left px-6 text-gray-200 font-semibold py-3 border-gray-600 border-b; } - & > div { + & > tr { @apply text-gray-200 transition-all duration-300 rounded hover:bg-gray-800; - & > div { + & > td { @apply py-1 px-6; } } &.custom-table-sm { - & > header > div { + & > thead > th { @apply px-3 py-2; } - & > div { - & > div { + & > tr { + & > td { @apply py-1 px-3; } } } &.custom-table-light { - & > header > div { + & > thead > th { @apply border-gray-500; } - & > div { + & > td { &:hover { @apply bg-gray-700; } diff --git a/resources/img/svg/lilie.svg b/resources/img/svg/lilie.svg new file mode 100644 index 00000000..9b10736a --- /dev/null +++ b/resources/img/svg/lilie.svg @@ -0,0 +1 @@ + diff --git a/resources/js/views/member/Index.vue b/resources/js/views/member/Index.vue index b82ae200..77f365e3 100644 --- a/resources/js/views/member/Index.vue +++ b/resources/js/views/member/Index.vue @@ -3,57 +3,61 @@ -
-
-
Nachname
-
Vorname
-
Straße
-
PLZ
-
Ort
-
Tags
-
Beitrag
-
Geburtstag
-
Rechnung
-
Ausstand
-
Eintritt
-
-
+ + + + + + + + + + + + + + + + -
-
-
-
-
-
-
+
+ + + + + + + + + + + + + + - +
NachnameVornameStraßePLZOrtTagsBeitragGeburtstagRechnungAusstandEintritt
+ +
M N C
- -
-
-
+
Kein
- -
+
- -
-
+
- - +
diff --git a/tailwind.config.js b/tailwind.config.js index 6740c505..49946484 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -13,6 +13,12 @@ module.exports = { extend: { }, colors: { + woelfling: '#ff6400', + jungpfadfinder: '#2f53a7', + pfadfinder: '#00823c', + rover: '#cc1f2f', + biber: '#ffed00', + leiter: '#9d9d9c', teal: [], primary: { 100: 'hsl(181, 98%, 93%)',