first commit

This commit is contained in:
root committed 2026-02-16 23:15:50 +01:00
commit 20767d392f
82 files changed
+15950

No files matched your search

@@ -0,0 +1,53 @@
<?php
namespace App\Filament\Resources\Orders;
use App\Filament\Resources\Orders\Pages\CreateOrder;
use App\Filament\Resources\Orders\Pages\EditOrder;
use App\Filament\Resources\Orders\Pages\ListOrders;
use App\Filament\Resources\Orders\Schemas\OrderForm;
use App\Filament\Resources\Orders\Tables\OrdersTable;
use App\Models\Order;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
class OrderResource extends Resource
{
protected static ?string $model = Order::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::ShoppingBag;
protected static ?string $navigationLabel = "Bestellungen";
protected static ?string $pluralLabel = "Bestellungen";
protected static ?string $pluralModelLabel = "Bestellungen";
protected static ?string $modelLabel = "Bestellung";
public static function form(Schema $schema): Schema
{
return OrderForm::configure($schema);
}
public static function table(Table $table): Table
{
return OrdersTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListOrders::route('/'),
'create' => CreateOrder::route('/create'),
'edit' => EditOrder::route('/{record}/edit'),
];
}
}
@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\Orders\Pages;
use App\Filament\Resources\Orders\OrderResource;
use Filament\Resources\Pages\CreateRecord;
class CreateOrder extends CreateRecord
{
protected static string $resource = OrderResource::class;
}
@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Orders\Pages;
use App\Filament\Resources\Orders\OrderResource;
use Filament\Actions\DeleteAction;
use Filament\Resources\Pages\EditRecord;
class EditOrder extends EditRecord
{
protected static string $resource = OrderResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
];
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Orders\Pages;
use App\Filament\Resources\Orders\OrderResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListOrders extends ListRecords
{
protected static string $resource = OrderResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}
@@ -0,0 +1,36 @@
<?php
namespace App\Filament\Resources\Orders\Schemas;
use App\Orderstatus;
use Filament\Actions\Action;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
class OrderForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->required(),
TextInput::make('url')
->suffixIcon(Heroicon::GlobeAlt)
->url(),
TextInput::make('count')
->required()
->numeric()
->default(1),
Select::make("orderstatus")->options(Orderstatus::class)->visibleOn(["edit"]),
DateTimePicker::make('orderdatetime')->visibleOn(["edit", "view"]),
Select::make('user_id')
->relationship("user", "name")
->required()
->default(filament()->auth()->user()->id),
])->columns(1);
}
}
@@ -0,0 +1,68 @@
<?php
namespace App\Filament\Resources\Orders\Tables;
use App\Orderstatus;
use Filament\Actions\Action;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Illuminate\Database\Eloquent\Collection;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\SelectColumn;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Model;
class OrdersTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('name')
->searchable(),
TextColumn::make('url')
->searchable()
->formatStateUsing(fn (string $state): string => substr($state, 0, 40)) ,
TextColumn::make('count')
->numeric()
->sortable(),
SelectColumn::make('orderstatus')->options(Orderstatus::class)
->searchable(),
TextColumn::make('user.name')
->numeric()
->sortable(),
])->striped()
->selectable()
->filters([
//
])
->recordActions([
Action::make("url_oeffnen")->icon(Heroicon::Link)->iconButton()->label("URL öffnen")->url(function (Model $record) { return $record->url;}, true),
EditAction::make()->iconButton()->label("Bearbeiten"),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
Action::make('bestellt')
->accessSelectedRecords()
->action(function (Collection $selectedRecords) {
$selectedRecords->each(
fn (Model $selectedRecord) => $selectedRecord->update([
'orderstatus' => Orderstatus::ORDERED,
]),
);
})->requiresConfirmation()->icon(Heroicon::ShoppingCart),
]),
]);
}
}
@@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\Users\Pages;
use App\Filament\Resources\Users\UserResource;
use Filament\Resources\Pages\CreateRecord;
class CreateUser extends CreateRecord
{
protected static string $resource = UserResource::class;
}
@@ -0,0 +1,21 @@
<?php
namespace App\Filament\Resources\Users\Pages;
use App\Filament\Resources\Users\UserResource;
use Filament\Actions\DeleteAction;
use Filament\Actions\ViewAction;
use Filament\Resources\Pages\EditRecord;
class EditUser extends EditRecord
{
protected static string $resource = UserResource::class;
protected function getHeaderActions(): array
{
return [
ViewAction::make(),
DeleteAction::make(),
];
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Users\Pages;
use App\Filament\Resources\Users\UserResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListUsers extends ListRecords
{
protected static string $resource = UserResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}
@@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\Users\Pages;
use App\Filament\Resources\Users\UserResource;
use Filament\Actions\EditAction;
use Filament\Resources\Pages\ViewRecord;
class ViewUser extends ViewRecord
{
protected static string $resource = UserResource::class;
protected function getHeaderActions(): array
{
return [
EditAction::make(),
];
}
}
@@ -0,0 +1,27 @@
<?php
namespace App\Filament\Resources\Users\Schemas;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
class UserForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextInput::make('name')
->required(),
TextInput::make('email')
->label('Email address')
->email()
->required(),
DateTimePicker::make('email_verified_at'),
TextInput::make('password')
->password()
->required(),
]);
}
}
@@ -0,0 +1,28 @@
<?php
namespace App\Filament\Resources\Users\Schemas;
use Filament\Infolists\Components\TextEntry;
use Filament\Schemas\Schema;
class UserInfolist
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
TextEntry::make('name'),
TextEntry::make('email')
->label('Email address'),
TextEntry::make('email_verified_at')
->dateTime()
->placeholder('-'),
TextEntry::make('created_at')
->dateTime()
->placeholder('-'),
TextEntry::make('updated_at')
->dateTime()
->placeholder('-'),
]);
}
}
@@ -0,0 +1,48 @@
<?php
namespace App\Filament\Resources\Users\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Actions\ViewAction;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
class UsersTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
TextColumn::make('name')
->searchable(),
TextColumn::make('email')
->label('Email address')
->searchable(),
TextColumn::make('email_verified_at')
->dateTime()
->sortable(),
TextColumn::make('created_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
TextColumn::make('updated_at')
->dateTime()
->sortable()
->toggleable(isToggledHiddenByDefault: true),
])
->filters([
//
])
->recordActions([
ViewAction::make(),
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
]),
]);
}
}
@@ -0,0 +1,61 @@
<?php
namespace App\Filament\Resources\Users;
use App\Filament\Resources\Users\Pages\CreateUser;
use App\Filament\Resources\Users\Pages\EditUser;
use App\Filament\Resources\Users\Pages\ListUsers;
use App\Filament\Resources\Users\Pages\ViewUser;
use App\Filament\Resources\Users\Schemas\UserForm;
use App\Filament\Resources\Users\Schemas\UserInfolist;
use App\Filament\Resources\Users\Tables\UsersTable;
use App\Models\User;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
class UserResource extends Resource
{
protected static ?string $model = User::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::Users;
protected static ?string $navigationLabel = "Benutzer";
protected static ?string $pluralLabel = "Benutzer";
protected static ?string $pluralModelLabel = "Benutzer";
protected static ?string $modelLabel = "Benutzer";
public static function form(Schema $schema): Schema
{
return UserForm::configure($schema);
}
public static function infolist(Schema $schema): Schema
{
return UserInfolist::configure($schema);
}
public static function table(Table $table): Table
{
return UsersTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListUsers::route('/'),
'create' => CreateUser::route('/create'),
'view' => ViewUser::route('/{record}'),
'edit' => EditUser::route('/{record}/edit'),
];
}
}
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace App\Http\Controllers;
abstract class Controller
{
//
}
+56
View File
@@ -0,0 +1,56 @@
<?php
namespace App\Mail;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class OrderArrived extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*/
public function __construct(
public Order $order,
)
{
//
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Bestellung angekommen',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
markdown: 'mail.order-arrived',
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+56
View File
@@ -0,0 +1,56 @@
<?php
namespace App\Mail;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class OrderRegistered extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*/
public function __construct(
public Order $order,
)
{
//
}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'Neue Bestellung',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
markdown: 'mail.order-registered',
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace App\Models;
use App\Observers\OrderObserver;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
#[ObservedBy([OrderObserver::class])]
class Order extends Model
{
protected $fillable = ["name", "url", "count", "orderstatus", "orderdatetime", "user_id"];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function orderstatus(): BelongsTo
{
return $this->belongsTo(Orderstatus::class);
}
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Orderstatus extends Model
{
protected $fillable = ['name'];
}
+55
View File
@@ -0,0 +1,55 @@
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable implements FilamentUser
{
/** @use HasFactory<\Database\Factories\UserFactory> */
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'name',
'email',
'password',
];
public function canAccessPanel(Panel $panel): bool
{
return str_ends_with($this->email, '@auerbach-stiftung.de') || str_ends_with($this->email, '@digital-infinity.de');
}
/**
* The attributes that should be hidden for serialization.
*
* @var list<string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}
+57
View File
@@ -0,0 +1,57 @@
<?php
namespace App\Observers;
use App\Mail\OrderArrived;
use App\Mail\OrderRegistered;
use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
class OrderObserver
{
/**
* Handle the Order "created" event.
*/
public function created(Order $order): void
{
$user = User::find(1);
Mail::to($user)->send(new OrderRegistered($order));
}
/**
* Handle the Order "updated" event.
*/
public function updated(Order $order): void
{
$orderstatusArrived = Orderstatus::find("name", "angekommen")->first();
if($order->orderstatus == $orderstatusArrived->id) {
$user = $order->usery;
Mail::to($user)->send(new OrderArrived($order));
}
}
/**
* Handle the Order "deleted" event.
*/
public function deleted(Order $order): void
{
//
}
/**
* Handle the Order "restored" event.
*/
public function restored(Order $order): void
{
//
}
/**
* Handle the Order "force deleted" event.
*/
public function forceDeleted(Order $order): void
{
//
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
//
}
}
@@ -0,0 +1,64 @@
<?php
namespace App\Providers\Filament;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\AuthenticateSession;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Pages\Dashboard;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
use Filament\Support\Enums\Width;
use Filament\Widgets\AccountWidget;
use Filament\Widgets\FilamentInfoWidget;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
class AdminPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->default()
->id('admin')
->path('/')
->login()
->spa()
->unsavedChangesAlerts()
->profile()
->passwordReset()
->colors([
'primary' => Color::Amber,
])
->discoverResources(in: app_path('Filament/Resources'), for: 'App\Filament\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\Filament\Pages')
->pages([
Dashboard::class,
])
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets')
->widgets([
AccountWidget::class,
FilamentInfoWidget::class,
])
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
])
->authMiddleware([
Authenticate::class,
]);
}
}