Add dashboard blocks
This commit is contained in:
parent
a16c0f469c
commit
5a97574a86
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace App\Efz;
|
||||
|
||||
use App\Home\Blocks\Block;
|
||||
use App\Member\Member;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class EfzPendingBlock extends Block
|
||||
{
|
||||
/**
|
||||
* @return Builder<Member>
|
||||
*/
|
||||
public function query(): Builder
|
||||
{
|
||||
return Member::where(function ($query) {
|
||||
return $query->where('efz', '<=', now()->subYears(5)->endOfYear())
|
||||
->orWhereNull('efz');
|
||||
})
|
||||
->orderByRaw('lastname, firstname')
|
||||
->whereHas('memberships', fn ($builder) => $builder->isLeader());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{member: array<int, string>}
|
||||
*/
|
||||
public function data(): array
|
||||
{
|
||||
return [
|
||||
'members' => $this->query()->get()->map(fn ($member) => $member->fullname)->toArray(),
|
||||
];
|
||||
}
|
||||
|
||||
public function component(): string
|
||||
{
|
||||
return 'efz-pending';
|
||||
}
|
||||
|
||||
public function title(): string
|
||||
{
|
||||
return 'Ausstehende Führungszeugnisse';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Home\Actions;
|
||||
|
||||
use App\Home\DashboardFactory;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia;
|
||||
use Inertia\Response;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class IndexAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
/**
|
||||
* @return array<array-key, mixed>
|
||||
*/
|
||||
public function handle(): array
|
||||
{
|
||||
return [
|
||||
'blocks' => app(DashboardFactory::class)->render(),
|
||||
];
|
||||
}
|
||||
|
||||
public function asController(Request $request): Response
|
||||
{
|
||||
session()->put('menu', 'dashboard');
|
||||
session()->put('title', 'Dashboard');
|
||||
|
||||
return Inertia::render('home/VIndex', $this->handle());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace App\Home\Blocks;
|
||||
|
||||
abstract class Block
|
||||
{
|
||||
abstract protected function data(): array;
|
||||
|
||||
abstract protected function title(): string;
|
||||
|
||||
abstract protected function component(): string;
|
||||
|
||||
/**
|
||||
* @return array{data: array<array-key, mixed>, title: string, component: string}
|
||||
*/
|
||||
public function render(): array
|
||||
{
|
||||
return [
|
||||
'data' => $this->data(),
|
||||
'title' => $this->title(),
|
||||
'component' => $this->component(),
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace App\Home;
|
||||
|
||||
use App\Efz\EfzPendingBlock;
|
||||
use App\Home\Blocks\Block;
|
||||
use App\Membership\AgeGroupCountBlock;
|
||||
use App\Membership\TestersBlock;
|
||||
use App\Payment\MemberPaymentBlock;
|
||||
|
||||
class DashboardFactory
|
||||
{
|
||||
/**
|
||||
* @var array<int, class-string<Block>>
|
||||
*/
|
||||
private array $blocks = [
|
||||
AgeGroupCountBlock::class,
|
||||
MemberPaymentBlock::class,
|
||||
TestersBlock::class,
|
||||
EfzPendingBlock::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @return array<array-key, mixed>
|
||||
*/
|
||||
public function render(): array
|
||||
{
|
||||
return collect($this->blocks)->map(fn ($block): array => app($block)->render())->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<Block> $block
|
||||
*/
|
||||
public function register(string $block): self
|
||||
{
|
||||
$this->blocks[] = $block;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function purge(): self
|
||||
{
|
||||
$this->blocks = [];
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Home;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class HomeServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
app()->singleton(DashboardFactory::class, fn () => new DashboardFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Home\Queries;
|
||||
|
||||
use App\Member\Membership;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class GroupQuery
|
||||
{
|
||||
/**
|
||||
* @var Builder<Membership>
|
||||
*/
|
||||
private Builder $query;
|
||||
|
||||
public function execute(): self
|
||||
{
|
||||
$this->query = Membership::select('subactivities.slug', 'subactivities.name')
|
||||
->selectRaw('COUNT(member_id) AS count')
|
||||
->join('activities', 'memberships.activity_id', 'activities.id')
|
||||
->join('subactivities', 'memberships.subactivity_id', 'subactivities.id')
|
||||
->isAgeGroup()
|
||||
->isMember()
|
||||
->groupBy('subactivities.slug', 'subactivities.name')
|
||||
->orderBy('subactivity_id');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{slug: string, name: string, count: int}>
|
||||
*/
|
||||
public function getResult(): array
|
||||
{
|
||||
return $this->query->get()->toArray();
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Views\HomeView;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Response;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
public function __invoke(Request $request): Response
|
||||
{
|
||||
session()->put('menu', 'dashboard');
|
||||
session()->put('title', 'Dashboard');
|
||||
|
||||
return \Inertia::render('home/VIndex', app(HomeView::class)->index($request));
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Views;
|
||||
|
||||
use App\Home\Queries\GroupQuery;
|
||||
use App\Member\Member;
|
||||
use App\Payment\Payment;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class HomeView
|
||||
{
|
||||
public function index(Request $request): array
|
||||
{
|
||||
/** @var object{a: string} */
|
||||
$amount = Payment::whereNeedsPayment()->selectRaw('sum(subscriptions.amount) AS a')->join('subscriptions', 'subscriptions.id', 'payments.subscription_id')->first();
|
||||
$members = Member::whereHasPendingPayment()->count();
|
||||
|
||||
return [
|
||||
'data' => [
|
||||
'payments' => [
|
||||
'users' => $members,
|
||||
'all_users' => Member::count(),
|
||||
'amount' => number_format($amount->a / 100, 2, ',', '.').' €',
|
||||
],
|
||||
'groups' => app(GroupQuery::class)->execute()->getResult(),
|
||||
'ending_tries' => MemberTriesResource::collection(Member::endingTries()->get()),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Views;
|
||||
|
||||
use App\Member\MemberResource;
|
||||
|
||||
/**
|
||||
* @mixin \App\Member\Member
|
||||
*/
|
||||
class MemberTriesResource extends MemberResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return array_merge(parent::toArray($request), [
|
||||
'try_ends_at' => $this->getModel()->try_created_at->addWeeks(8)->format('d.m.Y'),
|
||||
'try_ends_at_human' => $this->getModel()->try_created_at->addWeeks(8)->diffForHumans(),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -28,10 +28,9 @@ use Zoomyboy\LaravelNami\Api;
|
|||
use Zoomyboy\LaravelNami\Data\MembershipEntry;
|
||||
|
||||
/**
|
||||
* @property string $subscription_name
|
||||
* @property int $pending_payment
|
||||
* @property bool $is_confirmed
|
||||
* @property \Carbon\Carbon $try_created_at
|
||||
* @property string $subscription_name
|
||||
* @property int $pending_payment
|
||||
* @property bool $is_confirmed
|
||||
*/
|
||||
class Member extends Model
|
||||
{
|
||||
|
@ -356,19 +355,6 @@ class Member extends Model
|
|||
return $q;
|
||||
}
|
||||
|
||||
public function scopeEndingTries(Builder $q): Builder
|
||||
{
|
||||
return $q->whereHas('memberships', fn ($q) => $q
|
||||
->where('created_at', '<=', now()->subWeeks(7))
|
||||
->trying()
|
||||
)
|
||||
->addSelect([
|
||||
'try_created_at' => Membership::select('created_at')
|
||||
->whereColumn('memberships.member_id', 'members.id')
|
||||
->trying(),
|
||||
]);
|
||||
}
|
||||
|
||||
public static function fromVcard(string $url, string $data): static
|
||||
{
|
||||
$settings = app(NamiSettings::class);
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Membership;
|
||||
|
||||
use App\Home\Blocks\Block;
|
||||
use App\Member\Membership;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class AgeGroupCountBlock extends Block
|
||||
{
|
||||
/**
|
||||
* @return Builder<Membership>
|
||||
*/
|
||||
public function query(): Builder
|
||||
{
|
||||
return Membership::select('subactivities.slug', 'subactivities.name')
|
||||
->selectRaw('COUNT(member_id) AS count')
|
||||
->join('activities', 'memberships.activity_id', 'activities.id')
|
||||
->join('subactivities', 'memberships.subactivity_id', 'subactivities.id')
|
||||
->isAgeGroup()
|
||||
->isMember()
|
||||
->groupBy('subactivities.slug', 'subactivities.name')
|
||||
->orderBy('subactivity_id');
|
||||
}
|
||||
|
||||
protected function data(): array
|
||||
{
|
||||
return [
|
||||
'groups' => $this->query()->get()->toArray(),
|
||||
];
|
||||
}
|
||||
|
||||
public function component(): string
|
||||
{
|
||||
return 'age-group-count';
|
||||
}
|
||||
|
||||
public function title(): string
|
||||
{
|
||||
return 'Gruppierungs-Verteilung';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace App\Membership;
|
||||
|
||||
use App\Home\Blocks\Block;
|
||||
use App\Member\Member;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class TestersBlock extends Block
|
||||
{
|
||||
/**
|
||||
* @return Builder<Member>
|
||||
*/
|
||||
public function query(): Builder
|
||||
{
|
||||
return Member::whereHas('memberships', fn ($q) => $q
|
||||
->where('created_at', '<=', now()->subWeeks(7))
|
||||
->trying()
|
||||
)
|
||||
->with(['memberships' => fn ($query) => $query->trying()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{members: array<int, array{name: string, try_ends_at: string, try_ends_at_human: string}>}
|
||||
*/
|
||||
public function data(): array
|
||||
{
|
||||
return [
|
||||
'members' => $this->query()->get()->map(fn ($member) => [
|
||||
'name' => $member->fullname,
|
||||
'try_ends_at' => $member->memberships->first()->created_at->addWeeks(8)->format('d.m.Y'),
|
||||
'try_ends_at_human' => $member->memberships->first()->created_at->addWeeks(8)->diffForHumans(),
|
||||
])->toArray(),
|
||||
];
|
||||
}
|
||||
|
||||
public function component(): string
|
||||
{
|
||||
return 'testers';
|
||||
}
|
||||
|
||||
public function title(): string
|
||||
{
|
||||
return 'Endende Schhnupperzeiten';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Payment;
|
||||
|
||||
use App\Home\Blocks\Block;
|
||||
use App\Member\Member;
|
||||
|
||||
class MemberPaymentBlock extends Block
|
||||
{
|
||||
/**
|
||||
* @return array<string, string|int>
|
||||
*/
|
||||
public function data(): array
|
||||
{
|
||||
$amount = Payment::whereNeedsPayment()->selectRaw('sum(subscriptions.amount) AS nr')->join('subscriptions', 'subscriptions.id', 'payments.subscription_id')->first();
|
||||
$members = Member::whereHasPendingPayment()->count();
|
||||
|
||||
return [
|
||||
'members' => $members,
|
||||
'total_members' => Member::count(),
|
||||
'amount' => number_format($amount->nr / 100, 2, ',', '.').' €',
|
||||
];
|
||||
}
|
||||
|
||||
public function component(): string
|
||||
{
|
||||
return 'member-payment';
|
||||
}
|
||||
|
||||
public function title(): string
|
||||
{
|
||||
return 'Ausstehende Mitgliedsbeiträge';
|
||||
}
|
||||
}
|
|
@ -188,6 +188,7 @@ return [
|
|||
App\Tex\TexServiceProvider::class,
|
||||
App\Dav\ServiceProvider::class,
|
||||
App\Setting\SettingServiceProvider::class,
|
||||
App\Home\HomeServiceProvider::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<div>
|
||||
<div
|
||||
v-for="(group, index) in inner.groups"
|
||||
:key="index"
|
||||
class="flex mt-2 items-center leading-none text-gray-100"
|
||||
>
|
||||
<svg-sprite class="w-4 h-4 mr-2" src="lilie" :class="`text-${group.slug}`"></svg-sprite>
|
||||
<span v-text="group.name" class="grow"></span>
|
||||
<span v-text="group.count"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: function () {
|
||||
return {
|
||||
inner: {
|
||||
groups: [],
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
props: {
|
||||
data: {},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.inner = this.data;
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,31 @@
|
|||
<template>
|
||||
<div>
|
||||
<div
|
||||
v-for="(member, index) in inner.members"
|
||||
:key="index"
|
||||
class="flex mt-2 items-center leading-none text-gray-100"
|
||||
>
|
||||
<span class="grow" v-text="`${member}`"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: function () {
|
||||
return {
|
||||
inner: {
|
||||
members: [],
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
props: {
|
||||
data: {},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.inner = this.data;
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,26 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="text-gray-100">
|
||||
<span class="text-xl mr-1 font-semibold" v-text="inner.amount"></span>
|
||||
<span class="text-sm" v-text="`von ${inner.members} / ${inner.total_members} Mitgliedern`"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: function () {
|
||||
return {
|
||||
inner: {},
|
||||
};
|
||||
},
|
||||
|
||||
props: {
|
||||
data: {},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.inner = this.data;
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<div>
|
||||
<div
|
||||
v-for="(member, index) in inner.members"
|
||||
:key="index"
|
||||
class="flex mt-2 items-center leading-none text-gray-100"
|
||||
>
|
||||
<span class="grow" v-text="`${member.name}`"></span>
|
||||
<span class="mr-2 text-sm tex-gray-600" v-text="`${member.try_ends_at}`"></span>
|
||||
<span class="text-xs tex-gray-600" v-text="`${member.try_ends_at_human}`"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: function () {
|
||||
return {
|
||||
inner: {
|
||||
members: [],
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
props: {
|
||||
data: {},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.inner = this.data;
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -1,25 +1,16 @@
|
|||
<template>
|
||||
<div class="gap-6 grid-cols-4 grid p-6">
|
||||
<v-block v-for="(block, index) in blocks" :key="index" :title="block.title">
|
||||
<v-component :data="block.data" :is="block.component"></v-component>
|
||||
</v-block>
|
||||
<!--
|
||||
<v-block title="Ausstehende Mitgliedsbeiträge">
|
||||
<div class="text-gray-100">
|
||||
<span class="text-xl mr-1 font-semibold" v-text="data.payments.amount"></span>
|
||||
<span class="text-sm" v-text="`von ${data.payments.users} / ${data.payments.all_users} Mitgliedern`"></span>
|
||||
</div>
|
||||
</v-block>
|
||||
<v-block title="Gruppierungs-Verteilung">
|
||||
<div v-for="group, index in data.groups" :key="index" class="flex mt-2 items-center leading-none text-gray-100">
|
||||
<svg-sprite class="w-4 h-4 mr-2" src="lilie" :class="`text-${group.slug}`"></svg-sprite>
|
||||
<span v-text="group.name" class="grow"></span>
|
||||
<span v-text="group.count"></span>
|
||||
</div>
|
||||
</v-block>
|
||||
<v-block title="Endende Schhnupperzeiten">
|
||||
<div v-for="member, index in data.ending_tries" :key="index" class="flex mt-2 items-center leading-none text-gray-100">
|
||||
<span class="grow" v-text="`${member.firstname} ${member.lastname}`"></span>
|
||||
<span class="mr-2 text-sm tex-gray-600" v-text="`${member.try_ends_at}`"></span>
|
||||
<span class="text-xs tex-gray-600" v-text="`${member.try_ends_at_human}`"></span>
|
||||
</div>
|
||||
</v-block>
|
||||
-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -27,12 +18,15 @@
|
|||
export default {
|
||||
props: {
|
||||
data: {},
|
||||
blocks: {}
|
||||
blocks: {},
|
||||
},
|
||||
|
||||
components: {
|
||||
'VBlock': () => import('./VBlock')
|
||||
}
|
||||
|
||||
'VBlock': () => import('./VBlock'),
|
||||
'age-group-count': () => import('./AgeGroupCount.vue'),
|
||||
'efz-pending': () => import('./EfzPending.vue'),
|
||||
'testers': () => import('./Testers.vue'),
|
||||
'member-payment': () => import('./MemberPayment.vue'),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use App\Contribution\ContributionController;
|
||||
use App\Course\Controllers\CourseController;
|
||||
use App\Efz\ShowEfzDocumentAction;
|
||||
use App\Http\Controllers\HomeController;
|
||||
use App\Home\Actions\IndexAction as HomeIndexAction;
|
||||
use App\Initialize\Actions\InitializeAction;
|
||||
use App\Initialize\Actions\InitializeFormAction;
|
||||
use App\Member\Controllers\MemberResyncController;
|
||||
|
@ -22,7 +22,7 @@ Route::group(['namespace' => 'App\\Http\\Controllers'], function (): void {
|
|||
});
|
||||
|
||||
Route::group(['middleware' => 'auth:web'], function (): void {
|
||||
Route::get('/', HomeController::class)->name('home');
|
||||
Route::get('/', HomeIndexAction::class)->name('home');
|
||||
Route::get('/initialize', InitializeFormAction::class)->name('initialize.form');
|
||||
Route::post('/initialize', InitializeAction::class)->name('initialize.store');
|
||||
Route::resource('member', MemberController::class);
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Member\Member;
|
||||
use App\Member\Membership;
|
||||
use App\Home\Blocks\Block;
|
||||
use App\Home\DashboardFactory;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\TestCase;
|
||||
|
||||
|
@ -11,34 +11,39 @@ class HomeTest extends TestCase
|
|||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function testItDisplaysAgeGroups(): void
|
||||
public function testItDisplaysBlock(): void
|
||||
{
|
||||
$this->withoutExceptionHandling();
|
||||
Member::factory()->count(3)
|
||||
->has(Membership::factory()->in('€ Mitglied', 1, 'Biber', 2))
|
||||
->defaults()
|
||||
->create();
|
||||
Member::factory()->count(4)
|
||||
->has(Membership::factory()->in('€ Mitglied', 1, 'Wölfling', 3))
|
||||
->defaults()
|
||||
->create();
|
||||
Member::factory()->has(Membership::factory()->in('€ LeiterIn', 2, 'Wölfling', 3))
|
||||
->defaults()
|
||||
->create();
|
||||
app(DashboardFactory::class)->purge();
|
||||
app(DashboardFactory::class)->register(ExampleBlock::class);
|
||||
|
||||
$this->login()->loginNami();
|
||||
|
||||
$response = $this->get('/');
|
||||
|
||||
$this->assertInertiaHas([
|
||||
'slug' => 'biber',
|
||||
'name' => 'Biber',
|
||||
'count' => 3,
|
||||
], $response, 'data.groups.0');
|
||||
$this->assertInertiaHas([
|
||||
'slug' => 'woelfling',
|
||||
'name' => 'Wölfling',
|
||||
'count' => 4,
|
||||
], $response, 'data.groups.1');
|
||||
$this->assertInertiaHas(['class' => 'name'], $response, 'blocks.0.data');
|
||||
$this->assertInertiaHas('Example', $response, 'blocks.0.title');
|
||||
$this->assertInertiaHas('exa', $response, 'blocks.0.component');
|
||||
}
|
||||
}
|
||||
|
||||
class ExampleBlock extends Block
|
||||
{
|
||||
public function title(): string
|
||||
{
|
||||
return 'Example';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function data(): array
|
||||
{
|
||||
return ['class' => 'name'];
|
||||
}
|
||||
|
||||
public function component(): string
|
||||
{
|
||||
return 'exa';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Membership;
|
||||
|
||||
use App\Member\Member;
|
||||
use App\Member\Membership;
|
||||
use App\Membership\AgeGroupCountBlock;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AgeGroupCountBlockTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function testItDisplaysAgeGroups(): void
|
||||
{
|
||||
$this->withoutExceptionHandling();
|
||||
Member::factory()->count(3)
|
||||
->has(Membership::factory()->in('€ Mitglied', 1, 'Biber', 2))
|
||||
->defaults()
|
||||
->create();
|
||||
Member::factory()->count(4)
|
||||
->has(Membership::factory()->in('€ Mitglied', 1, 'Wölfling', 3))
|
||||
->defaults()
|
||||
->create();
|
||||
Member::factory()->has(Membership::factory()->in('€ LeiterIn', 2, 'Wölfling', 3))
|
||||
->defaults()
|
||||
->create();
|
||||
|
||||
$data = app(AgeGroupCountBlock::class)->render();
|
||||
|
||||
$this->assertEquals([
|
||||
'groups' => [
|
||||
['slug' => 'biber', 'name' => 'Biber', 'count' => 3],
|
||||
['slug' => 'woelfling', 'name' => 'Wölfling', 'count' => 4],
|
||||
],
|
||||
], $data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Membership;
|
||||
|
||||
use App\Efz\EfzPendingBlock;
|
||||
use App\Member\Member;
|
||||
use App\Member\Membership;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\TestCase;
|
||||
|
||||
class EfzPendingBlockTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function testItDisplaysEfzPending(): void
|
||||
{
|
||||
$this->withoutExceptionHandling();
|
||||
Member::factory()
|
||||
->has(Membership::factory()->in('€ LeiterIn', 1, 'Biber', 2))
|
||||
->defaults()
|
||||
->create(['firstname' => 'Max', 'lastname' => 'Muster', 'efz' => now()->subYear()]);
|
||||
Member::factory()
|
||||
->has(Membership::factory()->in('€ Mitglied', 1, 'Biber', 2))
|
||||
->defaults()
|
||||
->create(['firstname' => 'Jane', 'lastname' => 'Muster', 'efz' => now()->subYear()]);
|
||||
Member::factory()
|
||||
->has(Membership::factory()->in('€ LeiterIn', 1, 'Biber', 2))
|
||||
->defaults()
|
||||
->create(['firstname' => 'Mae', 'lastname' => 'Muster', 'efz' => now()->subYears(5)->startOfYear()]);
|
||||
Member::factory()
|
||||
->has(Membership::factory()->in('€ LeiterIn', 1, 'Biber', 2))
|
||||
->defaults()
|
||||
->create(['firstname' => 'Joe', 'lastname' => 'Muster', 'efz' => now()->subYears(5)->endOfYear()]);
|
||||
Member::factory()
|
||||
->has(Membership::factory()->in('€ LeiterIn', 1, 'Biber', 2))
|
||||
->defaults()
|
||||
->create(['firstname' => 'Moa', 'lastname' => 'Muster', 'efz' => null]);
|
||||
Member::factory()
|
||||
->has(Membership::factory()->in('€ Mitglied', 1, 'Biber', 2))
|
||||
->defaults()
|
||||
->create(['firstname' => 'Doe', 'lastname' => 'Muster', 'efz' => now()->subYears(5)]);
|
||||
|
||||
$data = app(EfzPendingBlock::class)->render()['data'];
|
||||
|
||||
$this->assertEquals([
|
||||
'members' => ['Joe Muster', 'Mae Muster', 'Moa Muster'],
|
||||
], $data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Membership;
|
||||
|
||||
use App\Member\Member;
|
||||
use App\Member\Membership;
|
||||
use App\Membership\TestersBlock;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\TestCase;
|
||||
|
||||
class TestersBlockTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function testItHasData(): void
|
||||
{
|
||||
$this->login()->loginNami();
|
||||
|
||||
Member::factory()
|
||||
->defaults()
|
||||
->has(Membership::factory()->in('Schnuppermitgliedschaft', 7, 'Wölfling', 8)->state(['created_at' => now()->subMonths(10)]))
|
||||
->create(['firstname' => 'Max', 'lastname' => 'Muster']);
|
||||
|
||||
$data = app(TestersBlock::class)->render();
|
||||
|
||||
$this->assertEquals([
|
||||
'members' => [
|
||||
[
|
||||
'name' => 'Max Muster',
|
||||
'try_ends_at' => now()->subMonths(10)->addWeeks(8)->format('d.m.Y'),
|
||||
'try_ends_at_human' => now()->subMonths(10)->addWeeks(8)->diffForHumans(),
|
||||
],
|
||||
],
|
||||
], $data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Payment;
|
||||
|
||||
use App\Member\Member;
|
||||
use App\Payment\MemberPaymentBlock;
|
||||
use App\Payment\Payment;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Tests\TestCase;
|
||||
|
||||
class TestersBlockTest extends TestCase
|
||||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function testItHasData(): void
|
||||
{
|
||||
$this->login()->loginNami();
|
||||
|
||||
Member::factory()
|
||||
->defaults()
|
||||
->has(Payment::factory()->notPaid()->subscription('example', 3400))
|
||||
->create();
|
||||
Member::factory()
|
||||
->defaults()
|
||||
->create();
|
||||
|
||||
$data = app(MemberPaymentBlock::class)->render();
|
||||
|
||||
$this->assertEquals([
|
||||
'amount' => '34,00 €',
|
||||
'members' => 1,
|
||||
'total_members' => 2,
|
||||
], $data);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue