Add mail view

This commit is contained in:
philipp lang 2024-07-04 23:54:37 +02:00
parent 6c44a25638
commit 793e4bacbd
11 changed files with 155 additions and 22 deletions

View File

@ -4,6 +4,7 @@ namespace App\Form\Actions;
use App\Form\Models\Participant;
use App\Prevention\Mails\PreventionRememberMail;
use App\Prevention\PreventionSettings;
use Illuminate\Support\Facades\Mail;
use Lorisleiva\Actions\Concerns\AsAction;
@ -26,11 +27,14 @@ class PreventionRememberAction
return;
}
$body = app(PreventionSettings::class)->formmail
->placeholder('formname', $participant->form->name);
if ($participant->getFields()->getMailRecipient() === null) {
continue;
}
Mail::send(new PreventionRememberMail($participant));
Mail::send(new PreventionRememberMail($participant, $body));
$participant->update(['last_remembered_at' => now()]);
}

View File

@ -0,0 +1,60 @@
<?php
namespace App\Lib\Editor;
use Spatie\LaravelData\Data;
class EditorData extends Data
{
public function __construct(
public string $version,
public array $blocks,
public int $time
) {
}
public function placeholder(string $search, string $replacement): self
{
$replacedBlocks = str(json_encode($this->blocks))->replace('{' . $search . '}', $replacement);
$this->blocks = json_decode($replacedBlocks);
return $this;
}
/**
* @param array<int, string> $wanted
*/
public function hasAll(array $wanted): bool
{
return collect($wanted)->first(fn ($search) => !str(json_encode($this->blocks))->contains($search)) === null;
}
public function replaceWithList(string $blockContent, array $replacements): self
{
$this->blocks = collect($this->blocks)->map(function ($block) use ($blockContent, $replacements) {
if (data_get($block, 'type') !== 'paragraph') {
return $block;
}
if (data_get($block, 'data.text') === '{' . $blockContent . '}') {
return [
...((array)$block),
'type' => 'list',
'data' => [
'style' => 'unordered',
'items' => collect($replacements)->map(fn ($replacement) => [
'content' => $replacement,
'items' => [],
]),
]
];
}
return $block;
})->toArray();
return $this;
}
}

View File

@ -2,6 +2,7 @@
namespace App\Prevention\Actions;
use App\Lib\Editor\EditorData;
use App\Lib\Events\Succeeded;
use App\Prevention\PreventionSettings;
use Lorisleiva\Actions\ActionRequest;
@ -20,7 +21,9 @@ class SettingStoreAction
public function handle(ActionRequest $request): void
{
app(PreventionSettings::class)->fill($request->validated())->save();
$settings = app(PreventionSettings::class);
$settings->formmail = EditorData::from($request->formmail);
$settings->save();
Succeeded::message('Einstellungen gespeichert.')->dispatch();
}

View File

@ -3,6 +3,7 @@
namespace App\Prevention\Mails;
use App\Invoice\InvoiceSettings;
use App\Lib\Editor\EditorData;
use App\Prevention\Contracts\Preventable;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Attachment;
@ -16,15 +17,15 @@ class PreventionRememberMail extends Mailable
use Queueable, SerializesModels;
public InvoiceSettings $settings;
public string $documents;
/**
* Create a new message instance.
*/
public function __construct(public Preventable $preventable)
public function __construct(public Preventable $preventable, public EditorData $bodyText)
{
$this->settings = app(InvoiceSettings::class);
$this->documents = collect($preventable->preventions())->map(fn ($prevention) => "* {$prevention->text()}")->implode("\n");
$this->bodyText = $this->bodyText
->replaceWithList('wanted', collect($preventable->preventions())->map(fn ($prevention) => $prevention->text())->toArray());
}
/**

View File

@ -2,6 +2,7 @@
namespace App\Prevention;
use App\Lib\Editor\EditorData;
use App\Prevention\Actions\PreventionIndexAction;
use App\Setting\Contracts\Indexable;
use App\Setting\LocalSettings;
@ -9,7 +10,7 @@ use App\Setting\LocalSettings;
class PreventionSettings extends LocalSettings implements Indexable
{
public array $formmail;
public EditorData $formmail;
public static function group(): string
{

View File

@ -6,6 +6,6 @@ return new class extends SettingsMigration
{
public function up(): void
{
$this->migrator->add('prevention.formmail', ['time' => 1, 'blocks' => []]);
$this->migrator->add('prevention.formmail', ['time' => 1, 'blocks' => [], 'version' => '1.0']);
}
};

View File

@ -1,11 +1,7 @@
@component('mail::message')
# Hallo {{ $preventable->member->fullname }},
Du hast dich für die Veranstaltung __{{$preventable->form->name}}__ angemeldet.
Damit du an der Veranstaltung als leitende oder helfende Person teilnehmen kannst, ist noch folgendes einzureichen oder zu beachten.
{!! $documents !!}
<x-mail-view::editor :content="$bodyText->toArray()['blocks']"></x-mail-view::editor>
@component('mail::subcopy')

View File

@ -13,10 +13,12 @@ use App\Prevention\Mails\PreventionRememberMail;
use App\Member\Member;
use App\Member\Membership;
use App\Prevention\PreventionSettings;
use BillSettings;
use Generator;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Mail;
use Tests\Lib\CreatesFormFields;
use Tests\RequestFactories\EditorRequestFactory;
use Tests\TestCase;
class PreventionTest extends TestCase
@ -176,12 +178,36 @@ class PreventionTest extends TestCase
InvoiceSettings::fake(['from_long' => 'Stamm Beispiel']);
$form = $this->createForm();
$participant = $this->createParticipant($form);
(new PreventionRememberMail($participant))
(new PreventionRememberMail($participant, app(PreventionSettings::class)->formmail))
->assertSeeInText($participant->member->firstname)
->assertSeeInText($participant->form->name)
->assertSeeInText('erweitertes Führungszeugnis')
->assertSeeInText('Stamm Beispiel')
->assertSeeInText($participant->member->lastname);
->assertSeeInText($participant->member->lastname)
->assertSeeInText('Stamm Beispiel');
}
public function testItRendersSetttingMail(): void
{
Mail::fake();
app(PreventionSettings::class)->fake([
'formmail' => EditorRequestFactory::new()->paragraphs(["lorem lala {formname} g", "{wanted}", "bbb"])->toData()
])->save();
$form = $this->createForm();
$this->createParticipant($form);
PreventionRememberAction::run();
Mail::assertSent(PreventionRememberMail::class, fn ($mail) => $mail->bodyText->hasAll([
'lorem lala ' . $form->name,
'erweitertes'
]));
}
public function testItDisplaysBodyTextInMail(): void
{
$form = $this->createForm();
$participant = $this->createParticipant($form);
$mail = new PreventionRememberMail($participant, EditorRequestFactory::new()->paragraphs(['ggtt'])->toData());
$mail->assertSeeInText('ggtt');
}
protected function createForm(): Form

View File

@ -23,7 +23,7 @@ class SettingTest extends TestCase
{
$this->login()->loginNami();
$text = EditorRequestFactory::new()->text(50, 'lorem ipsum')->create();
$text = EditorRequestFactory::new()->text(50, 'lorem ipsum')->toData();
app(PreventionSettings::class)->fill(['formmail' => $text])->save();
$this->get('/api/prevention')
@ -34,9 +34,7 @@ class SettingTest extends TestCase
{
$this->login()->loginNami();
$text = EditorRequestFactory::new()->text(50, 'new lorem')->create();
$this->post('/api/prevention', ['formmail' => $text])->assertOk();
$this->assertEquals($text, app(PreventionSettings::class)->formmail);
$this->post('/api/prevention', ['formmail' => EditorRequestFactory::new()->text(50, 'new lorem')->create()])->assertOk();
$this->assertTrue(app(PreventionSettings::class)->formmail->hasAll(['new lorem']));
}
}

View File

@ -2,6 +2,7 @@
namespace Tests\RequestFactories;
use App\Lib\Editor\EditorData;
use Worksome\RequestFactories\RequestFactory;
class EditorRequestFactory extends RequestFactory
@ -49,4 +50,28 @@ class EditorRequestFactory extends RequestFactory
],
];
}
/**
* @param array<int, string> $paragraphs
*/
public function paragraphs(array $paragraphs): self
{
return $this->state([
'time' => 1,
'version' => '1.0',
'blocks' => collect($paragraphs)->map(fn ($paragraph) => [
'id' => $this->faker->numberBetween([0, 10000]),
'type' => 'paragraph',
'data' => ['text' => $paragraph],
'tunes' => [
'condition' => ['mode' => 'all', 'ifs' => []]
]
])->toArray(),
]);
}
public function toData(): EditorData
{
return EditorData::from($this->create());
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Tests\Unit;
use Tests\RequestFactories\EditorRequestFactory;
use Tests\TestCase;
class EditorDataTest extends TestCase
{
public function testItReplacesBlockContentWithList(): void
{
$data = EditorRequestFactory::new()->paragraphs(['{search}'])->toData();
$data->replaceWithList('search', ['A', 'B']);
$this->assertEquals('A', data_get($data->blocks, '0.data.items.0.content'));
}
}