diff --git a/app/Actions/SendMail/SendNewsletter.php b/app/Actions/SendMail/SendNewsletter.php new file mode 100644 index 0000000..1f5dd13 --- /dev/null +++ b/app/Actions/SendMail/SendNewsletter.php @@ -0,0 +1,83 @@ + "Arch Versand 2026" + "mail_gruppen_id" => 1 + "mail_vorlage_id" => 2 + "sende_zeitpunkt" => "2026-05-08 10:00:00" + "versand_am" => null + "ist_active" => 0 + */ + + $template = MailVorlage::where('id', $record->mail_vorlage_id)->first(); + + /*** + "titel" => "Ein weiteres Beispiel" + "subjekt" => "Was ich noch sagen wollte" + "inhalt" => "

Hallo ###vorname###

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolor ▶" + */ + + $gruppe = MailGruppen::where('id', $record->mail_gruppen_id)->first(); + + /*** + "name" => "Test Versand" + "created_at" => "2026-05-06 06:42:16" + "absender_name" => "" + "absender_mail" => "" + */ + + $adressen = MailAdressen::where('mail_gruppen_id', $record->mail_gruppen_id)->where('deaktiviert', 0)->get(); + + /*** + "mail_gruppen_id" => 1 + "email" => "ht@webwerkstatt.tirol" + "company" => "WebWerkstatt.tirol" + "anrede" => "Freundschaftlich" + "gender" => "0" + "first_name" => "Hermann" + "last_name" => "Telser" + */ + + // dd($record, $template, $gruppe, $adressen); + + // "email" => "ht@webwerkstatt.tirol" + // "company" => "WebWerkstatt.tirol" + // "gender" => "0" + // "first_name" => "Hermann" + // "last_name" => "Telser" + + foreach ($adressen as $mail_data) { + + $mail_data->subjekt = $template->subjekt; + $mail_data->email = $template->email; + $mail_data->absender_name = $gruppe->absender_name; + $mail_data->absender_mail = $gruppe->absender_mail; + + if ($mail_data->anrede == 'Höflich') { + if ($mail_data->gender) { + $anrede = 'Sehr geehrte Frau '.$mail_data->last_name; + } else { + $anrede = 'Sehr geehrter Herr '.$mail_data->last_name; + } + } else { + $anrede = 'Hallo '.$mail_data->first_name; + } + + $mail_data->inhalt = str_replace('###anrede###', $anrede, $template->inhalt); + + SendNewsletterJob::dispatch($mail_data); + + } + } +} diff --git a/app/Filament/Resources/MailAdressens/Schemas/MailAdressenForm.php b/app/Filament/Resources/MailAdressens/Schemas/MailAdressenForm.php index b95ae49..fa3bf40 100644 --- a/app/Filament/Resources/MailAdressens/Schemas/MailAdressenForm.php +++ b/app/Filament/Resources/MailAdressens/Schemas/MailAdressenForm.php @@ -3,6 +3,7 @@ namespace App\Filament\Resources\MailAdressens\Schemas; use Filament\Forms\Components\DatePicker; +use Filament\Forms\Components\Radio; use Filament\Forms\Components\Select; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Toggle; @@ -30,12 +31,18 @@ class MailAdressenForm ->required() ->label('Mail Gruppe') ->relationship(name: 'mail_gruppen', titleAttribute: 'name'), - Toggle::make('im_newsletter')->label('Im Newsletter'), + Toggle::make('deaktiviert'), ]), Section::make('Persönliche Anrede') ->columns(2) ->columnSpanFull() ->schema([ + Radio::make('anrede') + ->required() + ->options([ + 'Höflich' => 'Höflich', + 'Freundschaftlich' => 'Freundschaftlich', + ]), Select::make('gender') ->required() ->label('Geschlecht') diff --git a/app/Filament/Resources/MailAdressens/Tables/MailAdressensTable.php b/app/Filament/Resources/MailAdressens/Tables/MailAdressensTable.php index ec84469..b33f2a1 100644 --- a/app/Filament/Resources/MailAdressens/Tables/MailAdressensTable.php +++ b/app/Filament/Resources/MailAdressens/Tables/MailAdressensTable.php @@ -25,13 +25,19 @@ class MailAdressensTable public static function configure(Table $table): Table { return $table + ->defaultSort('vereidigung', direction: 'desc') ->columns([ - ToggleColumn::make('im_newsletter') - ->onColor('success') - ->label('Senden'), - TextColumn::make('company')->label('Firma'), - TextColumn::make('email'), - TextColumn::make('vereidigung')->date()->sortable(), + ToggleColumn::make('deaktiviert') + ->alignCenter(), + TextColumn::make('anrede') + ->badge() + ->color(fn (string $state): string => match ($state) { + 'Höflich' => 'primary', + 'Freundschaftlich' => 'success', + default => 'gray', + }), + // TextColumn::make('company')->label('Firma') + // ->description(fn ($record): string => $record->first_name.' '.$record->last_name), TextColumn::make('gender') ->label('Geschlecht') ->formatStateUsing(fn (string $state): string => match ($state) { @@ -41,6 +47,8 @@ class MailAdressensTable }), TextColumn::make('first_name')->label('Vorname'), TextColumn::make('last_name')->label('Nachname'), + TextColumn::make('email'), + TextColumn::make('vereidigung')->date()->sortable(), ]) ->filters([ Filter::make('mail_gruppen_id') @@ -55,7 +63,7 @@ class MailAdressensTable ->options(function (): array { return MailGruppen::pluck('name', 'id')->toArray(); }), - Toggle::make('im_newsletter')->label('Im Newsletter'), + Toggle::make('deaktiviert')->label('Deaktivierte'), DatePicker::make('vereidigung_von')->native(false)->hiddenLabel()->placeholder('Vereidigung von'), DatePicker::make('vereidigung_bis')->native(false)->hiddenLabel()->placeholder('Vereidigung bis'), ]) @@ -65,8 +73,8 @@ class MailAdressensTable $data['mail_gruppen_id'], fn (Builder $query, $mail_gruppen_id): Builder => $query->where('mail_gruppen_id', $mail_gruppen_id), )->when( - $data['im_newsletter'], - fn (Builder $query, $im_newsletter): Builder => $query->where('im_newsletter', $im_newsletter), + $data['deaktiviert'], + fn (Builder $query, $deaktiviert): Builder => $query->where('deaktiviert', $deaktiviert), )->when( $data['vereidigung_von'], fn (Builder $query, $date): Builder => $query->whereDate('vereidigung', '>=', $date), @@ -87,35 +95,65 @@ class MailAdressensTable ]) ->toolbarActions([ BulkActionGroup::make([ - BulkAction::make('im_newsletter_on') - ->label('An Adressen senden') - ->tooltip('Ausgewählte Adressen dem Newsletter hinzufügen') - ->icon('heroicon-o-envelope') + BulkAction::make('deaktiviert_off') + ->label('Auswahl Aktivieren') + ->tooltip('Auswahl aktivieren') + ->icon('heroicon-o-play') + ->action(function (Collection $records, array $data): void { + foreach ($records as $record) { + /** @var object $record */ + MailAdressen::where('id', '=', $record->id) + ->update( + ['deaktiviert' => 0] + ); + } + }), + BulkAction::make('deaktiviert_on') + ->color('primary') + ->label('Auswahl Deaktivieren') + ->tooltip('Auswahl deaktivieren') + ->icon('heroicon-o-stop') + ->action(function (Collection $records, array $data): void { + foreach ($records as $record) { + /** @var object $record */ + MailAdressen::where('id', '=', $record->id) + ->update( + ['deaktiviert' => 1] + ); + } + }), + DeleteBulkAction::make()->label('Auswahl Löschen'), + ])->label('Status'), + BulkActionGroup::make([ + BulkAction::make('anrede_hoflich') + ->label('Auswahl Höflichkeitsform') + ->tooltip('Für ausgewählte Adressen Höflichkeitsform') + ->icon('heroicon-o-user-circle') + ->color('primary') + ->action(function (Collection $records, array $data): void { + foreach ($records as $record) { + /** @var object $record */ + MailAdressen::where('id', '=', $record->id) + ->update( + ['anrede' => 'Höflich'] + ); + } + }), + BulkAction::make('anrede_vertraulich') + ->label('Auswahl Freundschaftlich') + ->tooltip('Für ausgewählte Adressen freundschaftliche Anrede verwenden') ->color('success') + ->icon('heroicon-o-user') ->action(function (Collection $records, array $data): void { foreach ($records as $record) { /** @var object $record */ MailAdressen::where('id', '=', $record->id) ->update( - ['im_newsletter' => 1] + ['anrede' => 'Freundschaftlich'] ); } }), - BulkAction::make('im_newsletter_off') - ->label('Nicht an Adressen senden') - ->tooltip('Ausgewählte Adressen aus dem Newsletter herausnehmen') - ->icon('heroicon-o-envelope') - ->action(function (Collection $records, array $data): void { - foreach ($records as $record) { - /** @var object $record */ - MailAdressen::where('id', '=', $record->id) - ->update( - ['im_newsletter' => 0] - ); - } - }), - DeleteBulkAction::make(), - ]), + ])->label('Anrede'), ]); } } diff --git a/app/Filament/Resources/MailVersands/Schemas/MailVersandForm.php b/app/Filament/Resources/MailVersands/Schemas/MailVersandForm.php index 0ea02ac..a3b82aa 100644 --- a/app/Filament/Resources/MailVersands/Schemas/MailVersandForm.php +++ b/app/Filament/Resources/MailVersands/Schemas/MailVersandForm.php @@ -16,10 +16,12 @@ class MailVersandForm TextInput::make('name')->label('Benennung')->required(), DateTimePicker::make('sende_zeitpunkt')->native(false)->required(), Select::make('mail_gruppen_id') + ->label('Versand an Empfänger Grupper') ->required() ->relationship(name: 'mail_gruppen', titleAttribute: 'name'), Select::make('mail_vorlage_id') ->required() + ->label('Vorlage für den Versand') ->relationship(name: 'mail_vorlage', titleAttribute: 'titel'), ]); } diff --git a/app/Filament/Resources/MailVersands/Tables/MailVersandsTable.php b/app/Filament/Resources/MailVersands/Tables/MailVersandsTable.php index d2331c1..b640070 100644 --- a/app/Filament/Resources/MailVersands/Tables/MailVersandsTable.php +++ b/app/Filament/Resources/MailVersands/Tables/MailVersandsTable.php @@ -2,11 +2,11 @@ namespace App\Filament\Resources\MailVersands\Tables; +use App\Actions\SendMail\SendNewsletter; use Filament\Actions\Action; use Filament\Actions\EditAction; use Filament\Tables\Columns\SelectColumn; use Filament\Tables\Columns\TextColumn; -use Filament\Tables\Columns\ToggleColumn; use Filament\Tables\Table; class MailVersandsTable @@ -23,29 +23,44 @@ class MailVersandsTable ->optionsRelationship(name: 'mail_vorlage', titleAttribute: 'titel') ->label('Vorlage'), TextColumn::make('sende_zeitpunkt') + ->alignCenter() ->since() - ->dateTooltip() + ->badge() + ->dateTimeTooltip() ->label('Sende Zeitpunkt'), TextColumn::make('versand_am') + ->alignCenter() ->since() - ->dateTooltip(), - ToggleColumn::make('ist_active') - ->label('Senden') - ->tooltip('Wenn aktive wird der Newsletter zum eingestellten Zeitpunkt versand'), + ->badge() + ->dateTimeTooltip(), ]) ->filters([ // ]) ->recordActions([ - Action::make('testmail') - ->modalHeading('Sende Test-Mail') - ->modalIcon('heroicon-o-paper-airplane') - ->modalDescription('Eine Test-Mail wird an alle aktiven Benutzers der Test-Mail Gruppe gesandt.') + Action::make('sendmail-bytime') + ->tooltip('Sende zum Zeitpunkt') + ->modalHeading('Newsletter Versand') + ->icon('heroicon-o-envelope') + ->modalDescription('E-Mails werden gelisted und zum gewählten Datum versandt.') ->requiresConfirmation() ->modalSubmitActionLabel('Senden') ->iconButton() - ->icon('heroicon-o-paper-airplane'), - EditAction::make()->iconButton(), + ->modalIcon('heroicon-o-paper-airplane') + ->action(fn ($record) => SendNewsletter::mailit($record)), + Action::make('sendmail-now') + ->color('warning') + ->tooltip('Sende Jetzt') + ->modalHeading('Newsletter Versand') + ->icon('heroicon-o-envelope') + ->modalDescription('E-Mails werden gelisted und zum gewählten Datum versandt.') + ->requiresConfirmation() + ->modalSubmitActionLabel('Senden') + ->iconButton() + ->modalIcon('heroicon-o-paper-airplane') + ->action(fn ($record) => SendNewsletter::mailit($record)), + EditAction::make()->iconButton() + ->tooltip('Newsletter Einstellungen'), ]); } } diff --git a/app/Filament/Resources/MailVorlages/Schemas/MailVorlageForm.php b/app/Filament/Resources/MailVorlages/Schemas/MailVorlageForm.php index c771e9e..647c2c2 100644 --- a/app/Filament/Resources/MailVorlages/Schemas/MailVorlageForm.php +++ b/app/Filament/Resources/MailVorlages/Schemas/MailVorlageForm.php @@ -14,8 +14,9 @@ class MailVorlageForm return $schema ->components([ TextInput::make('titel')->suffix('Nur zur Kennung'), + TextInput::make('subjekt')->label('Betreff'), RichEditor::make('inhalt') - ->belowContent(new HtmlString('

Im Text können Vornamen und Nachnamen des Empfängers mit den Platzhaltern ###vorname### und ###nachname### ersetzen werden.
Für die Anrede wird der Platzhalter ###anrede### verwended. Dieser wird je nach Geschlecht durch "Sehr geehrte Frau" oder "Sehr geehrter Herr" ersetzt, oder einfach "Hallo" verwenden.
')) + ->belowContent(new HtmlString('
Im Text können Vornamen und Nachnamen des Empfängers mit den Platzhaltern ###vorname### und ###nachname### ersetzen werden.

Für die Anrede wird der Platzhalter ###anrede### verwendet.

Höflichkeitsform
Sehr geehrte Frau ###nachname###"
Sehr geehrter Herr ###nachname###

Freunschaftlich
Hallo ###vorname###
')) ->toolbarButtons([ ['bold', 'italic', 'underline', 'strike', 'code', 'small', 'highlight'], ['undo', 'redo'], diff --git a/app/Filament/Resources/MailVorlages/Tables/MailVorlagesTable.php b/app/Filament/Resources/MailVorlages/Tables/MailVorlagesTable.php index 0b4e215..00cd75e 100644 --- a/app/Filament/Resources/MailVorlages/Tables/MailVorlagesTable.php +++ b/app/Filament/Resources/MailVorlages/Tables/MailVorlagesTable.php @@ -3,8 +3,12 @@ namespace App\Filament\Resources\MailVorlages\Tables; use App\Models\MailVorlage; +use Filament\Actions\DeleteAction; use Filament\Actions\EditAction; use Filament\Forms\Components\Select; +use Filament\Support\Enums\TextSize; +use Filament\Tables\Columns\Layout\Split; +use Filament\Tables\Columns\Layout\Stack; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Enums\FiltersLayout; use Filament\Tables\Filters\Filter; @@ -17,18 +21,25 @@ class MailVorlagesTable { return $table ->columns([ - // TextColumn::make('titel'), - TextColumn::make('inhalt') - ->label('E-Mail Vorlage') - ->extraAttributes(['class' => 'tiptap']) - ->html() - ->wrap(), + Split::make([ + Stack::make([ + TextColumn::make('subjekt') + ->prefix('Betreff: ') + ->size(TextSize::Medium), + TextColumn::make('inhalt') + ->label('E-Mail Vorlage') + ->extraAttributes(['class' => 'tiptap']) + ->markdown() + ->wrap(), + ])->space(1), + ]), ]) ->paginated(false) ->filters([ Filter::make('vorlagen_id') ->schema([ Select::make('vorlagen_id') + ->searchable() ->hiddenLabel() ->preload() ->default(1) @@ -51,7 +62,8 @@ class MailVorlagesTable ->hiddenFilterIndicators() ->deferFilters(false) ->recordActions([ - EditAction::make(), + EditAction::make()->iconButton(), + DeleteAction::make()->iconButton(), ]); } } diff --git a/app/Jobs/SendNewsletterJob.php b/app/Jobs/SendNewsletterJob.php new file mode 100644 index 0000000..c0328fd --- /dev/null +++ b/app/Jobs/SendNewsletterJob.php @@ -0,0 +1,31 @@ +mail_data = $mail_data; + } + + /** + * Execute the job. + */ + public function handle(): void + { + Mail::to($this->mail_data->email)->send(new Newsletter($this->mail_data)); + } +} diff --git a/app/Mail/Newsletter.php b/app/Mail/Newsletter.php index 167467c..c591208 100644 --- a/app/Mail/Newsletter.php +++ b/app/Mail/Newsletter.php @@ -5,7 +5,6 @@ namespace App\Mail; use Illuminate\Bus\Queueable; use Illuminate\Mail\Mailable; use Illuminate\Mail\Mailables\Address; -use Illuminate\Mail\Mailables\Attachment; use Illuminate\Mail\Mailables\Content; use Illuminate\Mail\Mailables\Envelope; use Illuminate\Queue\SerializesModels; @@ -14,22 +13,24 @@ class Newsletter extends Mailable { use Queueable, SerializesModels; + public $mail_data; + /** * Create a new message instance. */ - public function __construct() + public function __construct($mail_data) { - // + $this->mail_data = $mail_data; } /** * Get the message envelope. */ - public function envelope($absender_email, $absender_name): Envelope + public function envelope(): Envelope { return new Envelope( - from: new Address($absender_email, $absender_name), - subject: 'Newsletter', + from: new Address($this->mail_data->absender_email, $this->mail_data->absender_name), + subject: $this->mail_data->subjekt, ); } @@ -42,14 +43,4 @@ class Newsletter extends Mailable view: 'mail.newsletter', ); } - - /** - * Get the attachments for the message. - * - * @return array - */ - public function attachments(): array - { - return []; - } } diff --git a/app/Models/MailAdressen.php b/app/Models/MailAdressen.php index c31c7fc..fd5a30c 100644 --- a/app/Models/MailAdressen.php +++ b/app/Models/MailAdressen.php @@ -9,6 +9,7 @@ class MailAdressen extends Model protected $fillable = [ 'mail_gruppen_id', 'email', + 'anrede', 'company', 'gender', 'first_name', @@ -17,7 +18,7 @@ class MailAdressen extends Model 'zip', 'city', 'vereidigung', - 'im_newsletter', + 'deaktiviert', ]; public function mail_gruppen() diff --git a/app/Models/MailVersand.php b/app/Models/MailVersand.php index b0ff3af..63ac688 100644 --- a/app/Models/MailVersand.php +++ b/app/Models/MailVersand.php @@ -12,7 +12,6 @@ class MailVersand extends Model 'mail_gruppen_id', 'sende_zeitpunkt', 'versand_am', - 'status', 'ist_active', ]; diff --git a/app/Models/MailVorlage.php b/app/Models/MailVorlage.php index ee8d9c3..8b7df27 100644 --- a/app/Models/MailVorlage.php +++ b/app/Models/MailVorlage.php @@ -8,6 +8,7 @@ class MailVorlage extends Model { protected $fillable = [ 'titel', + 'subjekt', 'inhalt', ]; } diff --git a/database/migrations/2026_05_04_070425_create_mail_adressens_table.php b/database/migrations/2026_05_04_070425_create_mail_adressens_table.php index 139835a..bd83fae 100644 --- a/database/migrations/2026_05_04_070425_create_mail_adressens_table.php +++ b/database/migrations/2026_05_04_070425_create_mail_adressens_table.php @@ -17,13 +17,14 @@ return new class extends Migration $table->string('email')->unique(); $table->string('company'); $table->string('gender')->nullable(); + $table->string('anrede')->nullable(); $table->string('first_name')->nullable(); $table->string('last_name')->nullable(); $table->string('address')->nullable(); $table->string('zip')->nullable(); $table->string('city')->nullable(); $table->timestamp('vereidigung')->nullable(); - $table->boolean('im_newsletter')->default(false); + $table->boolean('deaktiviert')->default(false); $table->timestamps(); }); } diff --git a/database/migrations/2026_05_05_150000_create_mail_vorlages_table.php b/database/migrations/2026_05_05_150000_create_mail_vorlages_table.php index d960faf..7328697 100644 --- a/database/migrations/2026_05_05_150000_create_mail_vorlages_table.php +++ b/database/migrations/2026_05_05_150000_create_mail_vorlages_table.php @@ -14,6 +14,7 @@ return new class extends Migration Schema::create('mail_vorlages', function (Blueprint $table) { $table->id(); $table->string('titel'); + $table->string('subjekt'); $table->longText('inhalt'); $table->timestamps(); }); diff --git a/database/migrations/2026_05_06_053208_create_mail_versands_table.php b/database/migrations/2026_05_06_053208_create_mail_versands_table.php index a4ba216..de81f34 100644 --- a/database/migrations/2026_05_06_053208_create_mail_versands_table.php +++ b/database/migrations/2026_05_06_053208_create_mail_versands_table.php @@ -16,9 +16,8 @@ return new class extends Migration $table->string('name'); $table->foreignId('mail_gruppen_id'); $table->foreignId('mail_vorlage_id'); - $table->date('sende_zeitpunkt'); - $table->date('versand_am')->nullable(); - $table->string('status')->nullable()->default('wartend'); + $table->timestamp('sende_zeitpunkt'); + $table->timestamp('versand_am')->nullable(); $table->boolean('ist_active')->default(0); $table->timestamps(); }); diff --git a/resources/css/filament/admin/theme.css b/resources/css/filament/admin/theme.css index 2736fe3..0d6263b 100644 --- a/resources/css/filament/admin/theme.css +++ b/resources/css/filament/admin/theme.css @@ -64,7 +64,7 @@ } .tiptap p { - margin: 0.5em 0; + margin: 0.7em 0; font-family: Verdana, Tahoma, sans-serif; font-size: 10pt; font-weight: normal; diff --git a/resources/views/mail/newsletter.blade.php b/resources/views/mail/newsletter.blade.php index 05c47dd..5a8d077 100644 --- a/resources/views/mail/newsletter.blade.php +++ b/resources/views/mail/newsletter.blade.php @@ -1,7 +1,40 @@ -
-

{{ $quote->name }}

-
- "{{ $quote->absender_mail }}" -
-

- {{ $quote->absender_name ?? 'Unknown' }}

-
+ + + + + + {{ $this->mail_data->subjekt }} + + + + +
+
+ {{ $this->mail_data->inhalt }} +
+
+ + +