Feature-Toggles, Administration, wiederkehrende Events und Event-Serien
- Administration & Rollenmanagement: Neuer Admin-Bereich mit Feature-Toggles und Sichtbarkeitseinstellungen pro Rolle (11 Toggles, 24 Visibility-Settings) - AdministrationController mit eigenem Settings-Tab, aus SettingsController extrahiert - Feature-Toggle-Guards in Controllers (Invitation, File, ListGenerator, Comment) und Views (events/show, events/edit, events/create) - Setting::isFeatureEnabled() und isFeatureVisibleFor() Hilfsmethoden - Wiederkehrende Trainings: Täglich/Wöchentlich/2-Wöchentlich mit Ende per Datum oder Anzahl (max. 52), Vorschau im Formular - Event-Serien: Verknüpfung über event_series_id (UUID), Modal-Dialog beim Speichern und Löschen mit Optionen "nur dieses" / "alle folgenden" - Löschen-Button direkt in der Event-Bearbeitung mit Serien-Dialog - DemoDataSeeder: 4 Trainings als Serie mit gemeinsamer event_series_id - Übersetzungen in allen 6 Sprachen (de, en, pl, ru, ar, tr) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
// Globale Feature-Toggles (Master-Schalter)
|
||||
$featureToggles = [
|
||||
['key' => 'feature_statistics', 'label' => 'Feature: Statistiken', 'type' => 'number', 'value' => '1'],
|
||||
['key' => 'feature_finances', 'label' => 'Feature: Finanzen', 'type' => 'number', 'value' => '1'],
|
||||
['key' => 'feature_catering', 'label' => 'Feature: Catering', 'type' => 'number', 'value' => '1'],
|
||||
['key' => 'feature_timekeepers', 'label' => 'Feature: Zeitnehmer', 'type' => 'number', 'value' => '1'],
|
||||
['key' => 'feature_carpools', 'label' => 'Feature: Fahrgemeinschaften', 'type' => 'number', 'value' => '1'],
|
||||
['key' => 'feature_comments', 'label' => 'Feature: Kommentare', 'type' => 'number', 'value' => '1'],
|
||||
['key' => 'feature_files', 'label' => 'Feature: Dateien', 'type' => 'number', 'value' => '1'],
|
||||
['key' => 'feature_faqs', 'label' => 'Feature: FAQs', 'type' => 'number', 'value' => '1'],
|
||||
['key' => 'feature_list_generator', 'label' => 'Feature: Listenerstellung', 'type' => 'number', 'value' => '1'],
|
||||
['key' => 'feature_invitations', 'label' => 'Feature: Einladungen', 'type' => 'number', 'value' => '1'],
|
||||
['key' => 'feature_player_stats', 'label' => 'Feature: Spielerstatistiken', 'type' => 'number', 'value' => '1'],
|
||||
];
|
||||
|
||||
foreach ($featureToggles as $toggle) {
|
||||
if (!Setting::where('key', $toggle['key'])->exists()) {
|
||||
$setting = new Setting([
|
||||
'label' => $toggle['label'],
|
||||
'type' => $toggle['type'],
|
||||
'value' => $toggle['value'],
|
||||
]);
|
||||
$setting->key = $toggle['key'];
|
||||
$setting->save();
|
||||
}
|
||||
}
|
||||
|
||||
// Neue pro-Rolle Visibility-Settings (zusätzlich zu bestehenden)
|
||||
$newVisibility = [
|
||||
'catering', 'timekeepers', 'carpools', 'comments',
|
||||
'files', 'faqs', 'list_generator', 'invitations', 'player_stats',
|
||||
];
|
||||
|
||||
foreach ($newVisibility as $feature) {
|
||||
foreach (['coach', 'parent_rep'] as $role) {
|
||||
$key = "visibility_{$feature}_{$role}";
|
||||
if (!Setting::where('key', $key)->exists()) {
|
||||
$setting = new Setting([
|
||||
'label' => ucfirst(str_replace('_', ' ', $feature)) . ': ' . ucfirst(str_replace('_', ' ', $role)),
|
||||
'type' => 'number',
|
||||
'value' => '1',
|
||||
]);
|
||||
$setting->key = $key;
|
||||
$setting->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$featureKeys = [
|
||||
'feature_statistics', 'feature_finances', 'feature_catering',
|
||||
'feature_timekeepers', 'feature_carpools', 'feature_comments',
|
||||
'feature_files', 'feature_faqs', 'feature_list_generator',
|
||||
'feature_invitations', 'feature_player_stats',
|
||||
];
|
||||
|
||||
Setting::whereIn('key', $featureKeys)->delete();
|
||||
|
||||
$newVisibility = [
|
||||
'catering', 'timekeepers', 'carpools', 'comments',
|
||||
'files', 'faqs', 'list_generator', 'invitations', 'player_stats',
|
||||
];
|
||||
|
||||
foreach ($newVisibility as $feature) {
|
||||
foreach (['coach', 'parent_rep'] as $role) {
|
||||
Setting::where('key', "visibility_{$feature}_{$role}")->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('events', function (Blueprint $table) {
|
||||
$table->string('event_series_id', 36)->nullable()->after('status')->index();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('events', function (Blueprint $table) {
|
||||
$table->dropIndex(['event_series_id']);
|
||||
$table->dropColumn('event_series_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user