Compare commits

..

13 Commits

Author SHA1 Message Date
philipp lang 5641006e2b Add mail data from template to form
continuous-integration/drone/push Build was killed Details
2024-07-15 17:13:23 +02:00
philipp lang 607038af6b Lint 2024-07-15 17:05:21 +02:00
philipp lang 189b83f2a5 Update migrations 2024-07-15 17:05:02 +02:00
philipp lang 3f4c655e5e Disable is_dirty when link not found 2024-07-15 17:00:42 +02:00
philipp lang 158cd2d352 Lint 2024-07-15 16:59:29 +02:00
philipp lang bf1388dbd9 Lint
continuous-integration/drone/push Build is passing Details
2024-07-14 22:16:34 +02:00
philipp lang aa20329a62 Lint
continuous-integration/drone/push Build is failing Details
2024-07-14 21:44:33 +02:00
philipp lang 09de9a5510 Add frontnd for formtemplate mails
continuous-integration/drone/push Build is failing Details
2024-07-14 20:53:26 +02:00
philipp lang 2982ae035f Lint 2024-07-14 20:53:15 +02:00
philipp lang 46740b14a2 Add mail_top and mail_bottom for formtemplates
continuous-integration/drone/push Build is failing Details
2024-07-14 20:20:56 +02:00
philipp lang 885eaa5df5 Fix migrations
continuous-integration/drone/push Build is failing Details
2024-07-14 20:19:17 +02:00
philipp lang 757042bdd2 Fix migrations
continuous-integration/drone/push Build is failing Details
2024-07-14 19:57:37 +02:00
philipp lang c3f6d3827b Add EditorData for forms texts
continuous-integration/drone/push Build is failing Details
2024-07-14 19:29:42 +02:00
25 changed files with 293 additions and 99 deletions

View File

@ -28,8 +28,6 @@ class FormStoreAction
'to' => 'required|date',
'registration_from' => 'present|nullable|date',
'registration_until' => 'present|nullable|date',
'mail_top' => 'array',
'mail_bottom' => 'array',
'header_image' => 'required|exclude',
'mailattachments' => 'present|array|exclude',
'is_active' => 'boolean',

View File

@ -30,8 +30,6 @@ class FormUpdateAction
'to' => 'required|date',
'registration_from' => 'present|nullable|date',
'registration_until' => 'present|nullable|date',
'mail_top' => 'array',
'mail_bottom' => 'array',
'is_active' => 'boolean',
'is_private' => 'boolean',
'export' => 'nullable|array',

View File

@ -28,6 +28,8 @@ trait HasValidation
'config.sections.*.fields.*.columns.mobile' => 'required|numeric|gt:0|lte:2',
'config.sections.*.fields.*.columns.tablet' => 'required|numeric|gt:0|lte:4',
'config.sections.*.fields.*.columns.desktop' => 'required|numeric|gt:0|lte:6',
'mail_top' => 'array',
'mail_bottom' => 'array',
];
}

View File

@ -19,9 +19,9 @@ class ConfirmRegistrationMail extends Mailable
public string $fullname;
public FormConfigData $config;
/** @var array<string, mixed> */
/** @var array<int, mixed> */
public array $topText;
/** @var array<string, mixed> */
/** @var array<int, mixed> */
public array $bottomText;
/**

View File

@ -32,9 +32,9 @@ class Form extends Model implements HasMedia
public $casts = [
'config' => FormConfigData::class,
'meta' => 'json',
'description' => 'json',
'mail_top' => 'json',
'mail_bottom' => 'json',
'description' => EditorData::class,
'mail_top' => EditorData::class,
'mail_bottom' => EditorData::class,
'is_active' => 'boolean',
'is_private' => 'boolean',
'export' => ExportData::class,

View File

@ -3,6 +3,7 @@
namespace App\Form\Models;
use App\Form\Data\FormConfigData;
use App\Lib\Editor\EditorData;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -17,5 +18,7 @@ class Formtemplate extends Model
public $casts = [
'config' => FormConfigData::class,
'mail_top' => EditorData::class,
'mail_bottom' => EditorData::class,
];
}

View File

@ -7,6 +7,7 @@ use App\Form\Enums\SpecialType;
use App\Form\Fields\Field;
use App\Form\Models\Formtemplate;
use App\Group;
use App\Lib\Editor\EditorData;
use App\Lib\HasMeta;
use Illuminate\Http\Resources\Json\JsonResource;
@ -52,6 +53,8 @@ class FormtemplateResource extends JsonResource
],
'default' => [
'name' => '',
'mail_top' => EditorData::default(),
'mail_bottom' => EditorData::default(),
'config' => [
'sections' => [],
]

View File

@ -8,12 +8,11 @@ abstract class ConditionResolver
abstract public function filterCondition(Condition $condition): bool;
/**
* @param array<string, mixed> $content
* @return array<string, mixed>
* @return array<int, mixed>
*/
public function makeBlocks(array $content): array
public function makeBlocks(EditorData $data): array
{
return array_filter(data_get($content, 'blocks', []), fn ($block) => $this->filterBlock($block));
return array_filter($data->blocks, fn ($block) => $this->filterBlock($block));
}
/**

View File

@ -43,15 +43,15 @@ class FormFactory extends Factory
{
return [
'name' => $this->faker->words(4, true),
'description' => EditorRequestFactory::new()->create(),
'description' => EditorRequestFactory::new()->toData(),
'excerpt' => $this->faker->words(10, true),
'config' => ['sections' => []],
'from' => $this->faker->dateTimeBetween('+1 week', '+4 weeks')->format('Y-m-d H:i:s'),
'to' => $this->faker->dateTimeBetween('+1 week', '+4 weeks')->format('Y-m-d H:i:s'),
'registration_from' => $this->faker->dateTimeBetween('-2 weeks', 'now')->format('Y-m-d H:i:s'),
'registration_until' => $this->faker->dateTimeBetween('now', '+2 weeks')->format('Y-m-d H:i:s'),
'mail_top' => EditorRequestFactory::new()->create(),
'mail_bottom' => EditorRequestFactory::new()->create(),
'mail_top' => EditorRequestFactory::new()->toData(),
'mail_bottom' => EditorRequestFactory::new()->toData(),
'is_active' => true,
'is_private' => false,
'export' => ExportData::from([]),
@ -85,16 +85,16 @@ class FormFactory extends Factory
public function mailTop(EditorRequestFactory $factory): self
{
return $this->state(['mail_top' => $factory->create()]);
return $this->state(['mail_top' => $factory->toData()]);
}
public function mailBottom(EditorRequestFactory $factory): self
{
return $this->state(['mail_bottom' => $factory->create()]);
return $this->state(['mail_bottom' => $factory->toData()]);
}
public function description(EditorRequestFactory $factory): self
{
return $this->state(['description' => $factory->create()]);
return $this->state(['description' => $factory->toData()]);
}
}

View File

@ -5,6 +5,7 @@ namespace Database\Factories\Form\Models;
use App\Form\Models\Formtemplate;
use Illuminate\Database\Eloquent\Factories\Factory;
use Tests\Feature\Form\FormtemplateSectionRequest;
use Tests\RequestFactories\EditorRequestFactory;
/**
* @extends Factory<Formtemplate>
@ -24,6 +25,8 @@ class FormtemplateFactory extends Factory
{
return [
'name' => $this->faker->words(4, true),
'mail_top' => EditorRequestFactory::new()->toData(),
'mail_bottom' => EditorRequestFactory::new()->toData(),
'config' => [
'sections' => [],
],
@ -45,4 +48,14 @@ class FormtemplateFactory extends Factory
{
return $this->state([str($method)->snake()->toString() => $parameters[0]]);
}
public function mailTop(EditorRequestFactory $factory): self
{
return $this->state(['mail_top' => $factory->toData()]);
}
public function mailBottom(EditorRequestFactory $factory): self
{
return $this->state(['mail_bottom' => $factory->toData()]);
}
}

View File

@ -1,10 +1,7 @@
<?php
use App\Form\Models\Form;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{

View File

@ -0,0 +1,57 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
foreach (DB::table('forms')->get() as $form) {
$mailTop = json_decode($form->mail_top, true);
if (!$mailTop || !count($mailTop)) {
DB::table('forms')->where('id', $form->id)->update(['mail_top' => $this->default()]);
}
$mailBottom = json_decode($form->mail_bottom, true);
if (!$mailBottom || !count($mailBottom)) {
DB::table('forms')->where('id', $form->id)->update(['mail_bottom' => $this->default()]);
}
$description = json_decode($form->description, true);
if (!$description || !count($description)) {
DB::table('forms')->where('id', $form->id)->update(['description' => $this->default()]);
}
}
Schema::table('forms', function (Blueprint $table) {
$table->json('description')->default($this->default())->change();
$table->json('mail_top')->default($this->default())->nullable(false)->change();
$table->json('mail_bottom')->default($this->default())->nullable(false)->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('forms', function (Blueprint $table) {
$table->json('description')->default(null)->change();
$table->json('mail_top')->default(null)->nullable(true)->change();
$table->json('mail_bottom')->default(null)->nullable(true)->change();
});
}
protected function default(): string
{
return json_encode(['time' => 4, 'blocks' => [], 'version' => '1.0']);
}
};

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('formtemplates', function (Blueprint $table) {
$table->json('mail_top')->after('name')->default(json_encode(['time' => 4, 'blocks' => [], 'version' => '1.0']));
$table->json('mail_bottom')->after('name')->default(json_encode(['time' => 4, 'blocks' => [], 'version' => '1.0']));
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('formtemplates', function (Blueprint $table) {
$table->dropColumn('mail_top');
$table->dropColumn('mail_bottom');
});
}
};

View File

@ -53,8 +53,8 @@
</div>
</template>
<script lang="js" setup>
import { ref, inject, computed } from 'vue';
<script setup>
import {ref, inject, computed} from 'vue';
const axios = inject('axios');
const emit = defineEmits(['update:modelValue']);
@ -70,19 +70,19 @@ const props = defineProps({
id: {
required: true,
type: String,
}
},
});
const comparatorOptions = ref([
{ id: 'isEqual', name: 'ist gleich', defaultValue: { DropdownField: null, RadioField: null, CheckboxField: false } },
{ id: 'isNotEqual', name: 'ist ungleich', defaultValue: { DropdownField: null, RadioField: null, CheckboxField: false } },
{ id: 'isIn', name: 'ist in', defaultValue: { DropdownField: [], RadioField: [], CheckboxField: false } },
{ id: 'isNotIn', name: 'ist nicht in', defaultValue: { DropdownField: [], RadioField: [], CheckboxField: false } },
{id: 'isEqual', name: 'ist gleich', defaultValue: {DropdownField: null, RadioField: null, CheckboxField: false}},
{id: 'isNotEqual', name: 'ist ungleich', defaultValue: {DropdownField: null, RadioField: null, CheckboxField: false}},
{id: 'isIn', name: 'ist in', defaultValue: {DropdownField: [], RadioField: [], CheckboxField: false}},
{id: 'isNotIn', name: 'ist nicht in', defaultValue: {DropdownField: [], RadioField: [], CheckboxField: false}},
]);
const modeOptions = ref([
{ id: 'all', name: 'alle Bedingungen müssen zutreffen' },
{ id: 'any', name: 'mindestens eine Bedingung muss zutreffen' },
{id: 'all', name: 'alle Bedingungen müssen zutreffen'},
{id: 'any', name: 'mindestens eine Bedingung muss zutreffen'},
]);
const fields = computed(() => {
@ -133,34 +133,39 @@ function getField(fieldName) {
function getOptions(fieldName) {
return getField(fieldName).options.map((o) => {
return { id: o, name: o };
return {id: o, name: o};
});
}
const fieldOptions = computed(() =>
fields.value.map((field) => {
return { id: field.key, name: field.name };
return {id: field.key, name: field.name};
})
);
function addCondition() {
emit('update:modelValue', {...props.modelValue, ifs: [
...props.modelValue.ifs,
{
field: null,
comparator: null,
value: null,
}
]});
emit('update:modelValue', {
...props.modelValue,
ifs: [
...props.modelValue.ifs,
{
field: null,
comparator: null,
value: null,
},
],
});
}
const locked = ref(false);
async function checkIfDirty() {
const response = await axios.post(props.single.links.is_dirty, { config: props.single.config });
const response = await axios.post(props.single.links.is_dirty, {config: props.single.config});
locked.value = response.data.result;
}
checkIfDirty();
if (props.single.links && props.single.links.is_dirty) {
checkIfDirty();
}
</script>

View File

@ -201,12 +201,12 @@ var { meta, data, reloadPage, create, single, edit, cancel, submit, remove, getF
const axios = inject('axios');
const toast = useToast();
const active = ref(0);
const activeMailTab = ref(0);
const deleting = ref(null);
const showing = ref(null);
const fileSettingPopup = ref(null);
const active = ref(0);
const activeMailTab = ref(0);
const tabs = [{ title: 'Allgemeines' }, { title: 'Formular' }, { title: 'Bestätigungs-E-Mail' }, { title: 'Export' }, { title: 'Prävention' }];
const mailTabs = [{ title: 'vor Daten' }, { title: 'nach Daten' }];
@ -228,6 +228,8 @@ const allFields = computed(() => {
function setTemplate(template) {
active.value = 0;
single.value.config = template.config;
single.value.mail_top = template.mail_top;
single.value.mail_bottom = template.mail_bottom;
}
async function saveFileConditions(conditions) {

View File

@ -24,11 +24,33 @@
</ui-popup>
<ui-popup v-if="single !== null" :heading="`Vorlage ${single.id ? 'bearbeiten' : 'erstellen'}`" full @close="cancel">
<form-builder v-model="single.config" :meta="meta">
<template #meta>
<f-text id="name" v-model="single.name" label="Name" required></f-text>
</template>
</form-builder>
<div class="flex flex-col mt-3">
<ui-tabs v-model="activeTab" :entries="tabs"></ui-tabs>
<form-builder v-if="activeTab === 0" v-model="single.config" :meta="meta">
<template #meta>
<f-text id="name" v-model="single.name" label="Name" required></f-text>
</template>
</form-builder>
<div v-show="activeTab === 1" class="grid gap-3">
<ui-note class="mt-2 col-span-full">
Hier kannst du die E-Mail anpassen, die nach der Anmeldung an den Teilnehmer verschickt wird.<br />
Es gibt dafür einen ersten E-Mail-Teil und einen zweiten E-Mail-Teil. Dazwischen werden die Daten des Teilnehmers aufgelistet.<br />
Die Anrede ("Hallo Max Mustermann") wird automatisch an den Anfang gesetzt.<br />
Außerdem kannst du Dateien hochladen, die automatisch mit angehangen werden.
</ui-note>
<ui-tabs v-model="activeMailTab" :entries="mailTabs"></ui-tabs>
<f-editor v-if="activeMailTab === 0" id="mail_top" v-model="single.mail_top" name="mail_top" label="E-Mail-Teil 1" :rows="8" conditions required>
<template #conditions="{data, resolve}">
<conditions-form id="mail_top_conditions" :single="single" :value="data" @save="resolve"> </conditions-form>
</template>
</f-editor>
<f-editor v-if="activeMailTab === 1" id="mail_bottom" v-model="single.mail_bottom" name="mail_bottom" label="E-Mail-Teil 2" :rows="8" conditions required>
<template #conditions="{data, resolve}">
<conditions-form id="mail_bottom_conditions" :single="single" :value="data" @save="resolve"> </conditions-form>
</template>
</f-editor>
</div>
</div>
<template #actions>
<a href="#" @click.prevent="submit">
<ui-sprite src="save" class="text-zinc-400 w-6 h-6"></ui-sprite>
@ -62,8 +84,13 @@
import { ref } from 'vue';
import { indexProps, useIndex } from '../../composables/useInertiaApiIndex.js';
import FormBuilder from './FormBuilder.vue';
import ConditionsForm from '../form/ConditionsForm.vue';
const deleting = ref(null);
const activeTab = ref(0);
const activeMailTab = ref(0);
const tabs = [{ title: 'Formular' }, { title: 'Bestätigungs-E-Mail' }];
const mailTabs = [{ title: 'vor Daten' }, { title: 'nach Daten' }];
const props = defineProps(indexProps);
var { meta, data, reloadPage, create, remove, single, edit, cancel, submit } = useIndex(props.data, 'invoice');

View File

@ -19,7 +19,6 @@ class FormIndexActionTest extends FormTestCase
{
Carbon::setTestNow(Carbon::parse('2023-03-03'));
$this->login()->loginNami()->withoutExceptionHandling();
Formtemplate::factory()->name('tname')->sections([FormtemplateSectionRequest::new()->name('sname')])->create();
$form = Form::factory()
->name('lala')
->excerpt('fff')
@ -58,8 +57,6 @@ class FormIndexActionTest extends FormTestCase
->assertInertiaPath('data.data.0.links.export', route('form.export', ['form' => $form]))
->assertInertiaPath('data.meta.links.store', route('form.store'))
->assertInertiaPath('data.meta.links.formtemplate_index', route('formtemplate.index'))
->assertInertiaPath('data.meta.templates.0.name', 'tname')
->assertInertiaPath('data.meta.templates.0.config.sections.0.name', 'sname')
->assertInertiaPath('data.meta.default.name', '')
->assertInertiaPath('data.meta.default.prevention_conditions', ['mode' => 'all', 'ifs' => []])
->assertInertiaPath('data.meta.default.prevention_text.version', '1.0')
@ -76,6 +73,27 @@ class FormIndexActionTest extends FormTestCase
->assertInertiaPath('data.meta.section_default.name', '');
}
public function testFormtemplatesHaveData(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
Formtemplate::factory()->name('tname')->sections([FormtemplateSectionRequest::new()->name('sname')->fields([
$this->textField('vorname')
])])
->mailTop(EditorRequestFactory::new()->text(10, 'lala'))
->mailBottom(EditorRequestFactory::new()->text(10, 'lalb'))
->create();
sleep(1);
$this->get(route('form.index'))
->assertOk()
->assertInertiaPath('data.meta.templates.0.name', 'tname')
->assertInertiaPath('data.meta.templates.0.name', 'tname')
->assertInertiaPath('data.meta.templates.0.config.sections.0.name', 'sname')
->assertInertiaPath('data.meta.templates.0.config.sections.0.fields.0.key', 'vorname')
->assertInertiaPath('data.meta.templates.0.mail_top.blocks.0.data.text', 'lala')
->assertInertiaPath('data.meta.templates.0.mail_bottom.blocks.0.data.text', 'lalb');
}
public function testItDisplaysExport(): void
{
$this->login()->loginNami()->withoutExceptionHandling();

View File

@ -241,24 +241,6 @@ class FormRegisterMailTest extends FormTestCase
}
}
public function testItSendsEmailWhenMailTopIsEmpty(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$participant = Participant::factory()->for(
Form::factory()
->fields([
$this->textField('firstname')->specialType(SpecialType::FIRSTNAME),
$this->textField('lastname')->specialType(SpecialType::LASTNAME),
])->state(['mail_top' => []])
)
->data(['firstname' => 'Max', 'lastname' => 'Muster'])
->create();
$mail = new ConfirmRegistrationMail($participant);
$mail->assertSeeInText('Max');
}
/**
* @dataProvider blockDataProvider
* @param array<string, mixed> $conditions

View File

@ -73,6 +73,14 @@ class FormRequest extends RequestFactory
return $this->state([str($method)->snake()->toString() => $args[0]]);
}
/**
* @param array<int, FormtemplateFieldRequest> $fields
*/
public function fields(array $fields): self
{
return $this->sections([FormtemplateSectionRequest::new()->fields($fields)]);
}
public function headerImage(string $fileName): self
{
UploadedFile::fake()->image($fileName, 1000, 1000)->storeAs('media-library', $fileName, 'temp');

View File

@ -41,9 +41,9 @@ class FormStoreActionTest extends FormTestCase
$this->assertEquals('formname', $form->name);
$this->assertEquals('lorem ipsum', $form->prevention_text->blocks[0]['data']['text']);
$this->assertEquals('avff', $form->excerpt);
$this->assertEquals($description->paragraphBlock(10, 'Lorem'), $form->description);
$this->assertEquals(json_decode('{"time":1,"blocks":[{"id":11,"type":"paragraph","data":{"text":"lala"},"tunes":{"condition":{"mode":"all","ifs":[]}}}],"version":"1.0"}', true), $form->mail_top);
$this->assertEquals(json_decode('{"time":1,"blocks":[{"id":12,"type":"paragraph","data":{"text":"lalab"},"tunes":{"condition":{"mode":"all","ifs":[]}}}],"version":"1.0"}', true), $form->mail_bottom);
$this->assertEquals('Lorem', $form->description->blocks[0]['data']['text']);
$this->assertEquals('lala', $form->mail_top->blocks[0]['data']['text']);
$this->assertEquals('lalab', $form->mail_bottom->blocks[0]['data']['text']);
$this->assertEquals('2023-05-04 01:00', $form->registration_from->format('Y-m-d H:i'));
$this->assertEquals(true, $form->is_active);
$this->assertEquals('2023-07-07 01:00', $form->registration_until->format('Y-m-d H:i'));

View File

@ -19,10 +19,8 @@ class FormUpdateActionTest extends FormTestCase
{
$this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->create();
$payload = FormRequest::new()->sections([
FormtemplateSectionRequest::new()->fields([
$this->dateField()->state(['max_today' => true]),
])
$payload = FormRequest::new()->fields([
$this->dateField()->state(['max_today' => true]),
])->create();
$this->patchJson(route('form.update', ['form' => $form]), $payload)
@ -33,6 +31,24 @@ class FormUpdateActionTest extends FormTestCase
$this->assertTrue($form->config->sections->get(0)->fields->get(0)->maxToday);
}
public function testItSetsTexts(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()->create();
$payload = FormRequest::new()->fields([])
->mailTop(EditorRequestFactory::new()->text(11, 'lala'))
->mailBottom(EditorRequestFactory::new()->text(12, 'lalab'))
->description(EditorRequestFactory::new()->text(12, 'desc'))
->create();
$this->patchJson(route('form.update', ['form' => $form]), $payload)
->assertOk();
$this->assertEquals('lala', $form->fresh()->mail_top->blocks[0]['data']['text']);
$this->assertEquals('lalab', $form->fresh()->mail_bottom->blocks[0]['data']['text']);
$this->assertEquals('desc', $form->fresh()->description->blocks[0]['data']['text']);
}
public function testItClearsFrontendCacheWhenFormUpdated(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
@ -56,17 +72,14 @@ class FormUpdateActionTest extends FormTestCase
public function testItUpdatesActiveColumnsWhenFieldRemoved(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()
->sections([FormtemplateSectionRequest::new()->fields([
$this->textField('firstname'),
$this->textField('geb'),
$this->textField('lastname'),
])])
$form = Form::factory()->fields([
$this->textField('firstname'),
$this->textField('geb'),
$this->textField('lastname'),
])
->create();
$payload = FormRequest::new()->sections([
FormtemplateSectionRequest::new()->fields([
$this->textField('firstname'),
])
$payload = FormRequest::new()->fields([
$this->textField('firstname'),
])->create();
$this->patchJson(route('form.update', ['form' => $form]), $payload)->assertSessionDoesntHaveErrors()->assertOk();
@ -113,14 +126,12 @@ class FormUpdateActionTest extends FormTestCase
{
$this->login()->loginNami()->withoutExceptionHandling();
$form = Form::factory()
->sections([FormtemplateSectionRequest::new()->fields([])])
->fields([])
->create();
$payload = FormRequest::new()->sections([
FormtemplateSectionRequest::new()->fields([
$this->textField('firstname'),
$this->textField('geb'),
$this->textField('lastname'),
])
$payload = FormRequest::new()->fields([
$this->textField('firstname'),
$this->textField('geb'),
$this->textField('lastname'),
])->create();
$this->patchJson(route('form.update', ['form' => $form]), $payload)->assertSessionDoesntHaveErrors()->assertOk();

View File

@ -83,6 +83,16 @@ class FormtemplateIndexActionTest extends TestCase
])
->assertInertiaPath('data.meta.default', [
'name' => '',
'mail_top' => [
'version' => '1.0',
'blocks' => [],
'time' => 0,
],
'mail_bottom' => [
'version' => '1.0',
'blocks' => [],
'time' => 0,
],
'config' => [
'sections' => [],
]

View File

@ -2,10 +2,13 @@
namespace Tests\Feature\Form;
use Tests\RequestFactories\EditorRequestFactory;
use Worksome\RequestFactories\RequestFactory;
/**
* @method self name(string $name)
* @method self mailTop(?EditorRequestFactory $content)
* @method self mailBottom(?EditorRequestFactory $content)
*/
class FormtemplateRequest extends RequestFactory
{
@ -33,6 +36,6 @@ class FormtemplateRequest extends RequestFactory
*/
public function __call(string $method, $args): self
{
return $this->state([$method => $args[0]]);
return $this->state([str($method)->snake()->toString() => $args[0]]);
}
}

View File

@ -10,6 +10,7 @@ use App\Lib\Events\Succeeded;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Event;
use Generator;
use Tests\RequestFactories\EditorRequestFactory;
class FormtemplateStoreActionTest extends FormTestCase
{
@ -20,14 +21,17 @@ class FormtemplateStoreActionTest extends FormTestCase
{
Event::fake([Succeeded::class]);
$this->login()->loginNami()->withoutExceptionHandling();
FormtemplateRequest::new()->name('testname')->sections([
$payload = FormtemplateRequest::new()->name('testname')->sections([
FormtemplateSectionRequest::new()->name('Persönliches')->fields([
$this->textField('a')->name('lala1')->columns(['mobile' => 2, 'tablet' => 2, 'desktop' => 1])->required(false)->hint('hhh')->intro('intro'),
$this->textareaField('b')->name('lala2')->required(false)->specialType(SpecialType::FIRSTNAME)->rows(10),
]),
])->fake();
])
->mailTop(EditorRequestFactory::new()->text(10, 'lala'))
->mailBottom(EditorRequestFactory::new()->text(10, 'lblb'))
->create();
$this->postJson(route('formtemplate.store'))->assertOk();
$this->postJson(route('formtemplate.store'), $payload)->assertOk();
$formtemplate = Formtemplate::latest()->first();
$this->assertEquals('Persönliches', $formtemplate->config->sections->get(0)->name);
@ -41,6 +45,8 @@ class FormtemplateStoreActionTest extends FormTestCase
$this->assertEquals(SpecialType::FIRSTNAME, $formtemplate->config->sections->get(0)->fields->get(1)->specialType);
$this->assertEquals(['mobile' => 2, 'tablet' => 2, 'desktop' => 1], $formtemplate->config->sections->get(0)->fields->get(0)->columns->toArray());
$this->assertEquals(10, $formtemplate->config->sections->get(0)->fields->get(1)->rows);
$this->assertEquals('lala', $formtemplate->mail_top->blocks[0]['data']['text']);
$this->assertEquals('lblb', $formtemplate->mail_bottom->blocks[0]['data']['text']);
$this->assertFalse($formtemplate->config->sections->get(0)->fields->get(0)->required);
Event::assertDispatched(Succeeded::class, fn (Succeeded $event) => $event->message === 'Vorlage gespeichert.');
}

View File

@ -2,10 +2,12 @@
namespace Tests\Feature\Form;
use App\Form\Models\Form;
use App\Form\Models\Formtemplate;
use App\Lib\Events\Succeeded;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Event;
use Tests\RequestFactories\EditorRequestFactory;
use Tests\TestCase;
class FormtemplateUpdateActionTest extends TestCase
@ -29,6 +31,22 @@ class FormtemplateUpdateActionTest extends TestCase
Event::assertDispatched(Succeeded::class, fn (Succeeded $event) => $event->message === 'Vorlage aktualisiert.');
}
public function testItUpdatesTexts(): void
{
$this->login()->loginNami()->withoutExceptionHandling();
$formtemplate = Formtemplate::factory()->create();
$payload = FormtemplateRequest::new()
->mailTop(EditorRequestFactory::new()->text(10, 'lala'))
->mailBottom(EditorRequestFactory::new()->text(10, 'lalb'))
->create();
$this->patchJson(route('formtemplate.update', ['formtemplate' => $formtemplate]), $payload)
->assertOk();
$this->assertEquals('lala', Formtemplate::first()->mail_top->blocks[0]['data']['text']);
$this->assertEquals('lalb', Formtemplate::first()->mail_bottom->blocks[0]['data']['text']);
}
public function testNameIsRequired(): void
{
$this->login()->loginNami();