Compare commits
4 Commits
7c867176c4
...
653d59fc18
Author | SHA1 | Date |
---|---|---|
philipp lang | 653d59fc18 | |
philipp lang | 528b716705 | |
philipp lang | 096224fe98 | |
philipp lang | 646ce647da |
|
@ -1,3 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
docker buildx build -f .docker/base.Dockerfile .
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dashboard\Actions;
|
||||
|
||||
use App\Dashboard\DashboardFactory;
|
||||
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(): Response
|
||||
{
|
||||
session()->put('menu', 'dashboard');
|
||||
session()->put('title', 'Dashboard');
|
||||
|
||||
return Inertia::render('dashboard/VIndex', $this->handle());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dashboard\Blocks;
|
||||
|
||||
abstract class Block
|
||||
{
|
||||
/**
|
||||
* @return array<array-key, mixed>
|
||||
*/
|
||||
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,49 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dashboard;
|
||||
|
||||
use App\Dashboard\Blocks\Block;
|
||||
use App\Efz\EfzPendingBlock;
|
||||
use App\Invoice\MemberPaymentBlock;
|
||||
use App\Member\PsPendingBlock;
|
||||
use App\Membership\AgeGroupCountBlock;
|
||||
use App\Membership\TestersBlock;
|
||||
|
||||
class DashboardFactory
|
||||
{
|
||||
/**
|
||||
* @var array<int, class-string<Block>>
|
||||
*/
|
||||
private array $blocks = [
|
||||
AgeGroupCountBlock::class,
|
||||
MemberPaymentBlock::class,
|
||||
TestersBlock::class,
|
||||
EfzPendingBlock::class,
|
||||
PsPendingBlock::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,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dashboard;
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use App\Dashboard\Actions\IndexAction as DashboardIndexAction;
|
||||
|
||||
class DashboardServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
app()->singleton(DashboardFactory::class, fn () => new DashboardFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
app(Router::class)->middleware(['web', 'auth:web'])->group(function ($router) {
|
||||
$router->get('/', DashboardIndexAction::class)->name('home');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Efz;
|
||||
|
||||
use Modules\Dashboard\Block;
|
||||
use App\Dashboard\Blocks\Block;
|
||||
use App\Member\Member;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
|
@ -41,9 +41,4 @@ class EfzPendingBlock extends Block
|
|||
{
|
||||
return 'Ausstehende Führungszeugnisse';
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
return '<div></div>';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Invoice;
|
||||
|
||||
use Modules\Dashboard\Block;
|
||||
use App\Dashboard\Blocks\Block;
|
||||
use App\Invoice\Models\InvoicePosition;
|
||||
use App\Member\Member;
|
||||
|
||||
|
@ -34,9 +34,4 @@ class MemberPaymentBlock extends Block
|
|||
{
|
||||
return 'Ausstehende Mitgliedsbeiträge';
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
return '<div></div>';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Member;
|
||||
|
||||
use Modules\Dashboard\Block;
|
||||
use App\Dashboard\Blocks\Block;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class PsPendingBlock extends Block
|
||||
|
@ -47,9 +47,4 @@ class PsPendingBlock extends Block
|
|||
{
|
||||
return 'Ausstehende Präventionsschulungen';
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
return '<div></div>';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Membership;
|
||||
|
||||
use Modules\Dashboard\Block;
|
||||
use App\Dashboard\Blocks\Block;
|
||||
use App\Member\Membership;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
|
@ -55,9 +55,4 @@ class AgeGroupCountBlock extends Block
|
|||
{
|
||||
return 'Gruppierungs-Verteilung';
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
return '<div></div>';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Membership;
|
||||
|
||||
use Modules\Dashboard\Block;
|
||||
use App\Dashboard\Blocks\Block;
|
||||
use App\Member\Member;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
|
@ -40,9 +40,4 @@ class TestersBlock extends Block
|
|||
{
|
||||
return 'Endende Schhnupperzeiten';
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
return '<div></div>';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ class AppServiceProvider extends ServiceProvider
|
|||
|
||||
app()->extend('media-library-helpers', fn ($p) => $p->put('form', Form::class));
|
||||
|
||||
Blade::componentNamespace('App\\View\\Ui', 'ui');
|
||||
Blade::componentNamespace('App\\View\\Mail', 'mail-view');
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
|
||||
class LivewireServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
Blade::componentNamespace('App\\View\\Ui', 'ui');
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
|
@ -168,7 +168,6 @@ return [
|
|||
*/
|
||||
App\Providers\AppServiceProvider::class,
|
||||
App\Providers\AuthServiceProvider::class,
|
||||
// App\Providers\BroadcastServiceProvider::class,
|
||||
App\Providers\EventServiceProvider::class,
|
||||
App\Providers\HorizonServiceProvider::class,
|
||||
App\Providers\RouteServiceProvider::class,
|
||||
|
@ -176,8 +175,10 @@ return [
|
|||
App\Tex\TexServiceProvider::class,
|
||||
App\Dav\ServiceProvider::class,
|
||||
App\Setting\SettingServiceProvider::class,
|
||||
Modules\Dashboard\DashboardServiceProvider::class,
|
||||
App\Dashboard\DashboardServiceProvider::class,
|
||||
App\Providers\PluginServiceProvider::class,
|
||||
// Modules\Dashboard\DashboardServiceProvider::class,
|
||||
// App\Providers\LivewireServiceProvider::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
namespace Modules\Dashboard;
|
||||
|
||||
use App\Efz\EfzPendingBlock;
|
||||
use App\Invoice\MemberPaymentBlock;
|
||||
use App\Member\PsPendingBlock;
|
||||
use App\Membership\AgeGroupCountBlock;
|
||||
use App\Membership\TestersBlock;
|
||||
use Modules\Invoice\MemberPaymentBlock;
|
||||
use Modules\Member\AgeGroupCountBlock;
|
||||
use Modules\Member\TestersBlock;
|
||||
use Modules\Prevention\EfzPendingBlock;
|
||||
use Modules\Prevention\PsPendingBlock;
|
||||
|
||||
class DashboardFactory
|
||||
{
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace Modules\Dashboard;
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Modules\Dashboard\Components\DashboardComponent;
|
||||
|
||||
class DashboardServiceProvider extends ServiceProvider
|
||||
{
|
||||
|
@ -23,5 +25,8 @@ class DashboardServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function boot()
|
||||
{
|
||||
app(Router::class)->middleware(['web', 'auth:web'])->group(function ($router) {
|
||||
$router->get('/', DashboardComponent::class)->name('home');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Modules\Invoice;
|
||||
|
||||
use Modules\Dashboard\Block;
|
||||
use App\Invoice\Models\InvoicePosition;
|
||||
use App\Member\Member;
|
||||
|
||||
class MemberPaymentBlock extends Block
|
||||
{
|
||||
/**
|
||||
* @return array<string, string|int>
|
||||
*/
|
||||
public function data(): array
|
||||
{
|
||||
$amount = InvoicePosition::whereHas('invoice', fn ($query) => $query->whereNeedsPayment())
|
||||
->selectRaw('sum(price) AS price')
|
||||
->first();
|
||||
$members = Member::whereHasPendingPayment()->count();
|
||||
|
||||
return [
|
||||
'members' => $members,
|
||||
'total_members' => Member::count(),
|
||||
'amount' => number_format((int) $amount->price / 100, 2, ',', '.') . ' €',
|
||||
];
|
||||
}
|
||||
|
||||
public function component(): string
|
||||
{
|
||||
return 'member-payment';
|
||||
}
|
||||
|
||||
public function title(): string
|
||||
{
|
||||
return 'Ausstehende Mitgliedsbeiträge';
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
return '<div></div>';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace Modules\Member;
|
||||
|
||||
use Modules\Dashboard\Block;
|
||||
use App\Member\Membership;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class AgeGroupCountBlock extends Block
|
||||
{
|
||||
/**
|
||||
* @return Builder<Membership>
|
||||
*/
|
||||
public function memberQuery(): 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()
|
||||
->active()
|
||||
->groupBy('subactivities.slug', 'subactivities.name')
|
||||
->orderBy('subactivity_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Builder<Membership>
|
||||
*/
|
||||
public function leaderQuery(): Builder
|
||||
{
|
||||
return Membership::selectRaw('"leiter" AS slug, "Leiter" AS name, COUNT(member_id) AS count')
|
||||
->join('activities', 'memberships.activity_id', 'activities.id')
|
||||
->join('subactivities', 'memberships.subactivity_id', 'subactivities.id')
|
||||
->active()
|
||||
->isLeader();
|
||||
}
|
||||
|
||||
protected function data(): array
|
||||
{
|
||||
return [
|
||||
'groups' => [
|
||||
...$this->memberQuery()->get()->toArray(),
|
||||
...$this->leaderQuery()->get()->toArray(),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function component(): string
|
||||
{
|
||||
return 'age-group-count';
|
||||
}
|
||||
|
||||
public function title(): string
|
||||
{
|
||||
return 'Gruppierungs-Verteilung';
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
return '<div></div>';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace Modules\Member;
|
||||
|
||||
use Modules\Dashboard\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->isTrying())
|
||||
->with('memberships', fn ($q) => $q->isTrying());
|
||||
}
|
||||
|
||||
/**
|
||||
* @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()->from->addWeeks(8)->format('d.m.Y'),
|
||||
'try_ends_at_human' => $member->memberships->first()->from->addWeeks(8)->diffForHumans(),
|
||||
])->toArray(),
|
||||
];
|
||||
}
|
||||
|
||||
public function component(): string
|
||||
{
|
||||
return 'testers';
|
||||
}
|
||||
|
||||
public function title(): string
|
||||
{
|
||||
return 'Endende Schhnupperzeiten';
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
return '<div></div>';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Modules\Prevention;
|
||||
|
||||
use Modules\Dashboard\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');
|
||||
})
|
||||
->whereCurrentGroup()
|
||||
->orderByRaw('lastname, firstname')
|
||||
->whereHas('memberships', fn ($builder) => $builder->isLeader()->active());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{members: 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';
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
return '<div></div>';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace Modules\Prevention;
|
||||
|
||||
use Modules\Dashboard\Block;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class PsPendingBlock extends Block
|
||||
{
|
||||
/**
|
||||
* @return Builder<Member>
|
||||
*/
|
||||
public function query(): Builder
|
||||
{
|
||||
return Member::where(function ($query) {
|
||||
$time = now()->subYears(5)->endOfYear();
|
||||
|
||||
return $query
|
||||
->orWhere(fn ($query) => $query->whereNull('ps_at')->whereNull('more_ps_at'))
|
||||
->orWhere(fn ($query) => $query->whereNull('ps_at')->where('more_ps_at', '<=', $time))
|
||||
->orWhere(fn ($query) => $query->where('ps_at', '<=', $time)->whereNull('more_ps_at'))
|
||||
->orWhere(fn ($query) => $query->where('ps_at', '>=', $time)->where('more_ps_at', '<=', $time));
|
||||
})
|
||||
->whereCurrentGroup()
|
||||
->orderByRaw('lastname, firstname')
|
||||
->whereHas('memberships', fn ($builder) => $builder->isLeader()->active());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{members: array{fullname: string}}
|
||||
*/
|
||||
public function data(): array
|
||||
{
|
||||
return [
|
||||
'members' => $this->query()->get()->map(fn ($member) => [
|
||||
'fullname' => $member->fullname,
|
||||
])->toArray(),
|
||||
];
|
||||
}
|
||||
|
||||
public function component(): string
|
||||
{
|
||||
return 'ps-pending';
|
||||
}
|
||||
|
||||
public function title(): string
|
||||
{
|
||||
return 'Ausstehende Präventionsschulungen';
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
return '<div></div>';
|
||||
}
|
||||
}
|
|
@ -17,7 +17,6 @@ use App\Course\Actions\CourseIndexAction;
|
|||
use App\Course\Actions\CourseStoreAction;
|
||||
use App\Invoice\Actions\InvoiceStoreAction;
|
||||
use App\Course\Actions\CourseUpdateAction;
|
||||
use Modules\Dashboard\Actions\IndexAction as DashboardIndexAction;
|
||||
use App\Efz\ShowEfzDocumentAction;
|
||||
use App\Fileshare\Actions\FileshareApiIndexAction;
|
||||
use App\Fileshare\Actions\FileshareStoreAction;
|
||||
|
@ -78,14 +77,12 @@ use App\Membership\Actions\MembershipDestroyAction;
|
|||
use App\Membership\Actions\MembershipStoreAction;
|
||||
use App\Membership\Actions\MembershipUpdateAction;
|
||||
use App\Payment\SubscriptionController;
|
||||
use Modules\Dashboard\Components\DashboardComponent;
|
||||
|
||||
Route::group(['namespace' => 'App\\Http\\Controllers'], function (): void {
|
||||
Auth::routes(['register' => false]);
|
||||
});
|
||||
|
||||
Route::group(['middleware' => 'auth:web'], function (): void {
|
||||
Route::get('/', DashboardComponent::class)->name('home');
|
||||
Route::post('/nami/login-check', NamiLoginCheckAction::class)->name('nami.login-check');
|
||||
Route::post('/nami/get-search-layer', NamiGetSearchLayerAction::class)->name('nami.get-search-layer');
|
||||
Route::post('/nami/search', NamiSearchAction::class)->name('nami.search');
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
*
|
||||
!.gitignore
|
Loading…
Reference in New Issue