Add condition for email files
This commit is contained in:
parent
4095d218bd
commit
adf0ae183e
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace App\Form\Actions;
|
||||
|
||||
use App\Form\Models\Form;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Lorisleiva\Actions\ActionRequest;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class IsDirtyAction
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public function handle(Form $form, ActionRequest $request): JsonResponse
|
||||
{
|
||||
$form->config = $request->input('config');
|
||||
|
||||
return response()->json([
|
||||
'result' => $form->isDirty('config'),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -62,7 +62,16 @@ class Form extends Model implements HasMedia
|
|||
->registerMediaConversions(function (Media $media) {
|
||||
$this->addMediaConversion('square')->fit(Manipulations::FIT_CROP, 400, 400);
|
||||
});
|
||||
$this->addMediaCollection('mailattachments');
|
||||
$this->addMediaCollection('mailattachments')
|
||||
->withDefaultProperties(fn () => [
|
||||
'conditions' => [],
|
||||
])
|
||||
->withPropertyValidation(fn () => [
|
||||
'conditions' => 'array',
|
||||
'conditions.*.field' => 'required',
|
||||
'conditions.*.comparator' => 'required',
|
||||
'conditions.*.value' => 'present',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -47,6 +47,7 @@ class FormResource extends JsonResource
|
|||
'participant_index' => route('form.participant.index', ['form' => $this->getModel()]),
|
||||
'update' => route('form.update', ['form' => $this->getModel()]),
|
||||
'destroy' => route('form.destroy', ['form' => $this->getModel()]),
|
||||
'is_dirty' => route('form.is-dirty', ['form' => $this->getModel()]),
|
||||
]
|
||||
];
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 3a7f5587550f27864a14236f2ef9af77e947966c
|
||||
Subproject commit d2f7f16e88fc3062573fe38e0e9ddef6f2b0ea55
|
|
@ -0,0 +1,129 @@
|
|||
<template>
|
||||
<ui-note class="mt-2" type="danger" v-if="locked">
|
||||
Dieses Formular wurde bereits bearbeitet.<br />
|
||||
Bitte speichere es erst ab und editiere dann die Bedingungen.
|
||||
</ui-note>
|
||||
|
||||
<div v-else>
|
||||
<div class="mt-2">Datei: {{ value.name }}</div>
|
||||
<ui-icon-button class="mt-4 mb-2" icon="plus" @click="addCondition">Bedingung einfügen</ui-icon-button>
|
||||
|
||||
<div v-for="(condition, index) in conditions" class="grid grid-cols-[1fr_1fr_1fr_max-content] gap-2">
|
||||
<f-select :options="fieldOptions" v-model="condition.field" :id="`field-${index}`" :name="`field-${index}`" label="Feld"></f-select>
|
||||
<f-select
|
||||
:options="comparatorOptions"
|
||||
:model-value="condition.comparator"
|
||||
@update:model-value="updateComparator(condition, $event)"
|
||||
:id="`comparator-${index}`"
|
||||
:name="`comparator-${index}`"
|
||||
label="Vergleich"
|
||||
></f-select>
|
||||
<f-select
|
||||
v-if="condition.field && ['isEqual', 'isNotEqual'].includes(condition.comparator)"
|
||||
:options="getOptions(condition.field)"
|
||||
v-model="condition.value"
|
||||
:id="`value-${index}`"
|
||||
:name="`value-${index}`"
|
||||
label="Wert"
|
||||
></f-select>
|
||||
<f-multipleselect
|
||||
v-if="condition.field && ['isIn', 'isNotIn'].includes(condition.comparator)"
|
||||
:options="getOptions(condition.field)"
|
||||
v-model="condition.value"
|
||||
:id="`value-${index}`"
|
||||
:name="`value-${index}`"
|
||||
label="Wert"
|
||||
></f-multipleselect>
|
||||
<ui-action-button tooltip="Löschen" icon="trash" class="btn-danger self-end h-8" @click="conditions.splice(index, 1)"></ui-action-button>
|
||||
</div>
|
||||
|
||||
<ui-icon-button class="mt-4 mb-2" icon="save" @click="save">Speichern</ui-icon-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref, inject, computed} from 'vue';
|
||||
const axios = inject('axios');
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const props = defineProps({
|
||||
value: {
|
||||
required: true,
|
||||
},
|
||||
single: {
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const comparatorOptions = ref([
|
||||
{id: 'isEqual', name: 'ist gleich', defaultValue: null},
|
||||
{id: 'isNotEqual', name: 'ist ungleich', defaultValue: null},
|
||||
{id: 'isIn', name: 'ist in', defaultValue: []},
|
||||
{id: 'isNotIn', name: 'ist nicht in', defaultValue: []},
|
||||
]);
|
||||
|
||||
const fields = computed(() => {
|
||||
const result = [];
|
||||
props.single.config.sections.forEach((section) => {
|
||||
section.fields.forEach((field) => {
|
||||
if (['DropdownField', 'RadioField', 'CheckboxField'].includes(field.type)) {
|
||||
result.push(field);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
function updateComparator(condition, comparator) {
|
||||
condition.value = comparatorOptions.value.find((c) => c.id === comparator).defaultValue;
|
||||
condition.comparator = comparator;
|
||||
}
|
||||
|
||||
function getField(fieldName) {
|
||||
return fields.value.find((f) => f.key === fieldName);
|
||||
}
|
||||
|
||||
function getOptions(fieldName) {
|
||||
return getField(fieldName).options.map((o) => {
|
||||
return {id: o, name: o};
|
||||
});
|
||||
}
|
||||
|
||||
const fieldOptions = computed(() =>
|
||||
fields.value.map((field) => {
|
||||
return {id: field.key, name: field.name};
|
||||
})
|
||||
);
|
||||
|
||||
const conditions = ref('conditions' in props.value.properties ? props.value.properties.conditions : []);
|
||||
|
||||
const locked = ref(false);
|
||||
|
||||
function addCondition() {
|
||||
conditions.value.push({
|
||||
field: null,
|
||||
comparator: null,
|
||||
value: null,
|
||||
});
|
||||
}
|
||||
|
||||
async function save() {
|
||||
await axios.patch(`/mediaupload/${props.value.id}`, {
|
||||
properties: {
|
||||
...props.value.properties,
|
||||
conditions: conditions.value,
|
||||
},
|
||||
});
|
||||
|
||||
emit('close');
|
||||
}
|
||||
|
||||
async function checkIfDirty() {
|
||||
const response = await axios.post(props.single.links.is_dirty, {config: props.single.config});
|
||||
|
||||
locked.value = response.data.result;
|
||||
}
|
||||
|
||||
checkIfDirty();
|
||||
</script>
|
|
@ -84,7 +84,14 @@
|
|||
:parent-id="single.id"
|
||||
collection="mailattachments"
|
||||
class="row-span-2"
|
||||
></f-multiplefiles>
|
||||
>
|
||||
<template #buttons="{file, buttonClass, iconClass}">
|
||||
<a v-tooltip="`Bedingungen`" href="#" :class="[buttonClass, 'bg-blue-200', 'relative']" @click.prevent="fileSettingPopup = file">
|
||||
<div v-if="file.properties.conditions.length" class="absolute w-2 h-2 -mt-[0.05rem] -ml-[0.05rem] flex-none bg-red-900 rounded-full top-0 left-0"></div>
|
||||
<ui-sprite src="setting" :class="[iconClass, 'text-blue-800']"></ui-sprite>
|
||||
</a>
|
||||
</template>
|
||||
</f-multiplefiles>
|
||||
<f-textarea id="mail_bottom" v-model="single.mail_bottom" name="mail_bottom" label="E-Mail-Teil 2" rows="8" required></f-textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -95,6 +102,10 @@
|
|||
</template>
|
||||
</ui-popup>
|
||||
|
||||
<ui-popup v-if="fileSettingPopup !== null" heading="Bedingungen bearbeiten" @close="fileSettingPopup = null">
|
||||
<file-settings @close="fileSettingPopup = null" :single="single" :value="fileSettingPopup"></file-settings>
|
||||
</ui-popup>
|
||||
|
||||
<page-filter breakpoint="xl">
|
||||
<f-text id="search" :model-value="getFilter('search')" name="search" label="Suchen …" size="sm" @update:model-value="setFilter('search', $event)"></f-text>
|
||||
<f-switch id="past" :model-value="getFilter('past')" label="vergangene zeigen" size="sm" @update:model-value="setFilter('past', $event)"></f-switch>
|
||||
|
@ -142,6 +153,7 @@ import {ref} from 'vue';
|
|||
import {indexProps, useIndex} from '../../composables/useInertiaApiIndex.js';
|
||||
import FormBuilder from '../formtemplate/FormBuilder.vue';
|
||||
import Participants from './Participants.vue';
|
||||
import FileSettings from './FileSettings.vue';
|
||||
|
||||
const props = defineProps(indexProps);
|
||||
var {meta, data, reloadPage, create, single, edit, cancel, submit, remove, getFilter, setFilter} = useIndex(props.data, 'form');
|
||||
|
@ -149,6 +161,7 @@ var {meta, data, reloadPage, create, single, edit, cancel, submit, remove, getFi
|
|||
const active = ref(0);
|
||||
const deleting = ref(null);
|
||||
const showing = ref(null);
|
||||
const fileSettingPopup = ref(null);
|
||||
|
||||
const tabs = [{title: 'Allgemeines'}, {title: 'Formular'}, {title: 'E-Mail'}, {title: 'Export'}];
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ use App\Form\Actions\FormtemplateStoreAction;
|
|||
use App\Form\Actions\FormtemplateUpdateAction;
|
||||
use App\Form\Actions\FormUpdateAction;
|
||||
use App\Form\Actions\FormUpdateMetaAction;
|
||||
use App\Form\Actions\IsDirtyAction;
|
||||
use App\Form\Actions\ParticipantIndexAction;
|
||||
use App\Initialize\Actions\InitializeAction;
|
||||
use App\Initialize\Actions\InitializeFormAction;
|
||||
|
@ -160,4 +161,5 @@ Route::group(['middleware' => 'auth:web'], function (): void {
|
|||
Route::post('/form', FormStoreAction::class)->name('form.store');
|
||||
Route::patch('/form/{form}/meta', FormUpdateMetaAction::class)->name('form.update-meta');
|
||||
Route::get('/form/{form}/participants', ParticipantIndexAction::class)->name('form.participant.index');
|
||||
Route::post('/form/{form}/is-dirty', IsDirtyAction::class)->name('form.is-dirty');
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue