Compare commits
6 Commits
2a1107f59b
...
6bcea543fb
Author | SHA1 | Date |
---|---|---|
|
6bcea543fb | |
|
9ca06fd064 | |
|
9a6eba5fd9 | |
|
d41f24fdea | |
|
da567e0a73 | |
|
3ba29b9f5e |
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Contribution\Actions;
|
||||||
|
|
||||||
|
use App\Contribution\ContributionFactory;
|
||||||
|
use App\Country;
|
||||||
|
use Inertia\Inertia;
|
||||||
|
use Inertia\Response;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
|
class FormAction
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function handle(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'countries' => Country::select('name', 'id')->get(),
|
||||||
|
'data' => [
|
||||||
|
'country' => Country::firstWhere('name', 'Deutschland')->id,
|
||||||
|
],
|
||||||
|
'compilers' => app(ContributionFactory::class)->compilerSelect(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asController(): Response
|
||||||
|
{
|
||||||
|
session()->put('menu', 'contribution');
|
||||||
|
session()->put('title', 'Zuschüsse');
|
||||||
|
|
||||||
|
return Inertia::render('contribution/VIndex', $this->handle());
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,10 +32,6 @@ class AppServiceProvider extends ServiceProvider
|
||||||
|
|
||||||
Blade::componentNamespace('App\\View\\Mail', 'mail-view');
|
Blade::componentNamespace('App\\View\\Mail', 'mail-view');
|
||||||
Model::preventLazyLoading(!app()->isProduction());
|
Model::preventLazyLoading(!app()->isProduction());
|
||||||
|
|
||||||
Blade::directive('rawAttribute', function ($expression) {
|
|
||||||
return '<?php if ($attributes->has("' . $expression . '.raw")): ?> <?php echo $attributes->get("' . $expression . '.raw"); ?> <?php else: ?> <?php echo "`".e($attributes->get("' . $expression . '"))."`"; ?> <?php endif ?>';
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,7 +27,7 @@ class Editor extends Component
|
||||||
return <<<'HTML'
|
return <<<'HTML'
|
||||||
<div class="flex flex-col group {{$heightClass}}">
|
<div class="flex flex-col group {{$heightClass}}">
|
||||||
@if ($label)
|
@if ($label)
|
||||||
<x-form::label :required="$required" :value="$label" />
|
<x-form::label :required="$required">{{$label}}</x-form::label>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="relative w-full h-full">
|
<div class="relative w-full h-full">
|
||||||
|
@ -41,7 +41,7 @@ class Editor extends Component
|
||||||
@updated="$wire.{{$attributes->wire('model')->value}} = $event.detail"
|
@updated="$wire.{{$attributes->wire('model')->value}} = $event.detail"
|
||||||
x-data="editor($wire.{{$attributes->wire('model')->value}})"
|
x-data="editor($wire.{{$attributes->wire('model')->value}})"
|
||||||
id="{{$id}}"
|
id="{{$id}}"
|
||||||
{{$attributes->except(['label', ':label'])}}
|
{{$attributes}}
|
||||||
></div>
|
></div>
|
||||||
<x-ui::errors :for="$name" />
|
<x-ui::errors :for="$name" />
|
||||||
@if($hint)
|
@if($hint)
|
||||||
|
|
|
@ -3,17 +3,15 @@
|
||||||
namespace App\View\Form;
|
namespace App\View\Form;
|
||||||
|
|
||||||
use App\View\Traits\HasFormDimensions;
|
use App\View\Traits\HasFormDimensions;
|
||||||
use App\View\Traits\RendersAlpine;
|
|
||||||
use Illuminate\View\Component;
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
class Label extends Component
|
class Label extends Component
|
||||||
{
|
{
|
||||||
|
|
||||||
use HasFormDimensions;
|
use HasFormDimensions;
|
||||||
use RendersAlpine;
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public bool $required = false,
|
public bool $required = false,
|
||||||
public string $value = ''
|
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,11 +19,10 @@ class Label extends Component
|
||||||
{
|
{
|
||||||
return <<<'HTML'
|
return <<<'HTML'
|
||||||
<span class="font-semibold leading-none text-gray-400 group-[.size-default]:text-sm group-[.size-sm]:text-xs">
|
<span class="font-semibold leading-none text-gray-400 group-[.size-default]:text-sm group-[.size-sm]:text-xs">
|
||||||
<span x-text="{!! $asAlpineString($attributes, 'value') !!}"></span>
|
{{ $slot }}
|
||||||
<template x-if="{!! $asAlpineBool($attributes, 'required') !!}">
|
@if ($required)
|
||||||
<span class="text-red-800"> *</span>
|
<span class="text-red-800"> *</span>
|
||||||
</template>
|
@endif
|
||||||
{{$attributes}}
|
|
||||||
</span>
|
</span>
|
||||||
HTML;
|
HTML;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,10 +29,10 @@ class Lever extends Component
|
||||||
return <<<'HTML'
|
return <<<'HTML'
|
||||||
<label class="flex flex-col items-start group {{$heightClass}} " for="{{$id}}" style="{{$heightVars}}">
|
<label class="flex flex-col items-start group {{$heightClass}} " for="{{$id}}" style="{{$heightVars}}">
|
||||||
@if ($label)
|
@if ($label)
|
||||||
<x-form::label :required="$required" :value="$label" />
|
<x-form::label :required="$required">{{$label}}</x-form::label>
|
||||||
@endif
|
@endif
|
||||||
<span class="relative flex-none flex h-[var(--height)] @if($hint) pr-8 @endif">
|
<span class="relative flex-none flex h-[var(--height)] @if($hint) pr-8 @endif">
|
||||||
<input id="{{$id}}" type="checkbox" name="{{$name}}" value="{{$value}}" @if($disabled) disabled="disabled" @endif class="absolute peer opacity-0" {{ $attributes->except('label.raw') }} />
|
<input id="{{$id}}" type="checkbox" name="{{$name}}" value="{{$value}}" @if($disabled) disabled="disabled" @endif class="absolute peer opacity-0" {{ $attributes }} />
|
||||||
<span class="relative cursor-pointer h-full w-[calc(var(--height)*2)] rounded peer-focus:bg-red-500 duration-300 bg-gray-700 peer-checked:bg-primary-700"></span>
|
<span class="relative cursor-pointer h-full w-[calc(var(--height)*2)] rounded peer-focus:bg-red-500 duration-300 bg-gray-700 peer-checked:bg-primary-700"></span>
|
||||||
<span class="absolute h-full top-0 left-0 flex-none flex justify-center items-center aspect-square">
|
<span class="absolute h-full top-0 left-0 flex-none flex justify-center items-center aspect-square">
|
||||||
<x-ui::sprite
|
<x-ui::sprite
|
||||||
|
|
|
@ -29,11 +29,11 @@ class Select extends Component
|
||||||
return <<<'HTML'
|
return <<<'HTML'
|
||||||
<label class="flex flex-col group {{$heightClass}}" for="{{$id}}" style="{{$heightVars}}">
|
<label class="flex flex-col group {{$heightClass}}" for="{{$id}}" style="{{$heightVars}}">
|
||||||
@if ($label)
|
@if ($label)
|
||||||
<x-form::label :required="$required" :value="$label"></x-form::label>
|
<x-form::label :required="$required">{{$label}}</x-form::label>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="relative flex-none flex">
|
<div class="relative flex-none flex">
|
||||||
<select {{$attributes->except(['label', ':label'])}} @if($disabled) disabled @endif name="{{$name}}" id="{{$id}}"
|
<select {{$attributes}} @if($disabled) disabled @endif name="{{$name}}" id="{{$id}}"
|
||||||
class="
|
class="
|
||||||
w-full h-[var(--height)] border-gray-600 border-solid text-gray-300 bg-gray-700 leading-none rounded-lg
|
w-full h-[var(--height)] border-gray-600 border-solid text-gray-300 bg-gray-700 leading-none rounded-lg
|
||||||
group-[.size-default]:border-2 group-[.size-sm]:border
|
group-[.size-default]:border-2 group-[.size-sm]:border
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
namespace App\View\Form;
|
namespace App\View\Form;
|
||||||
|
|
||||||
use App\View\Traits\HasFormDimensions;
|
use App\View\Traits\HasFormDimensions;
|
||||||
use App\View\Traits\RendersAlpine;
|
|
||||||
use Illuminate\View\Component;
|
use Illuminate\View\Component;
|
||||||
|
|
||||||
class Text extends Component
|
class Text extends Component
|
||||||
{
|
{
|
||||||
|
|
||||||
use HasFormDimensions;
|
use HasFormDimensions;
|
||||||
use RendersAlpine;
|
|
||||||
|
public string $id;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public string $name,
|
public string $name,
|
||||||
|
@ -18,23 +18,17 @@ class Text extends Component
|
||||||
public ?string $hint = null,
|
public ?string $hint = null,
|
||||||
public bool $required = false,
|
public bool $required = false,
|
||||||
public string $label = '',
|
public string $label = '',
|
||||||
public string $type = 'text',
|
public string $type = 'text'
|
||||||
public string $id = '',
|
|
||||||
) {
|
) {
|
||||||
if (!$id) {
|
|
||||||
$this->id = str()->uuid()->toString();
|
$this->id = str()->uuid()->toString();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return <<<'HTML'
|
return <<<'HTML'
|
||||||
<label {{ $attributes->merge(['class' => 'flex flex-col group '.$heightClass])->only('class') }}
|
<label {{ $attributes->merge(['class' => 'flex flex-col group '.$heightClass])->only('class') }} for="{{$id}}" style="{{$heightVars}}">
|
||||||
@if ($attributes->has(':id')) :for="{{$attributes->get(':id')}}" @else for="{{$id}}" @endif
|
@if ($label)
|
||||||
style="{{$heightVars}}"
|
<x-form::label :required="$required">{{$label}}</x-form::label>
|
||||||
>
|
|
||||||
@if ($hasAlpineAttribute($attributes, 'label'))
|
|
||||||
<x-form::label {{$attributes->merge(['value' => 'lalala', 'required' => false]) }} ></x-form::label>
|
|
||||||
@endif
|
@endif
|
||||||
<div class="relative flex-none flex">
|
<div class="relative flex-none flex">
|
||||||
<input
|
<input
|
||||||
|
@ -48,7 +42,7 @@ class Text extends Component
|
||||||
group-[.size-default]:text-sm group-[.size-sm]:text-xs
|
group-[.size-default]:text-sm group-[.size-sm]:text-xs
|
||||||
group-[.size-default]:p-2 group-[.size-sm]:p-1
|
group-[.size-default]:p-2 group-[.size-sm]:p-1
|
||||||
"
|
"
|
||||||
{{ $attributes->except(['class', 'label', ':label']) }}
|
{{ $attributes->except('class') }}
|
||||||
/>
|
/>
|
||||||
<x-ui::errors :for="$name" />
|
<x-ui::errors :for="$name" />
|
||||||
@if($hint)
|
@if($hint)
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\View\Traits;
|
|
||||||
|
|
||||||
use Illuminate\View\ComponentAttributeBag;
|
|
||||||
|
|
||||||
trait RendersAlpine
|
|
||||||
{
|
|
||||||
|
|
||||||
public function hasAlpineAttribute(ComponentAttributeBag $attributes, string $attribute): bool
|
|
||||||
{
|
|
||||||
return $this->{$attribute} || ($attributes->has(':' . $attribute) && $attributes->get(':' . $attribute));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function asAlpineString(ComponentAttributeBag $attributes, string $tagName): string
|
|
||||||
{
|
|
||||||
$rawTag = ':' . $tagName;
|
|
||||||
|
|
||||||
if ($attributes->has($rawTag) && $attributes->get($rawTag)) {
|
|
||||||
return $attributes->get($rawTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
$output = e($this->{$tagName});
|
|
||||||
return str($output)->swap([
|
|
||||||
'`' => '\\`',
|
|
||||||
'$' => '\\$',
|
|
||||||
'{' => '\\{',
|
|
||||||
'}' => '\\}',
|
|
||||||
])->wrap('`');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function asAlpineBool(ComponentAttributeBag $attributes, string $tagName): string
|
|
||||||
{
|
|
||||||
$rawTag = ':' . $tagName;
|
|
||||||
|
|
||||||
if ($attributes->has($rawTag)) {
|
|
||||||
return $attributes->get($rawTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->{$tagName} ? 'true' : 'false';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function renderAlpineFallbackAttribute(ComponentAttributeBag $attributes, string $tagName, string $prop): string
|
|
||||||
{
|
|
||||||
return ':label="aaa"';
|
|
||||||
|
|
||||||
return new ComponentAttributeBag([]);
|
|
||||||
return $attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function ca(ComponentAttributeBag $attributes): ComponentAttributeBag
|
|
||||||
{
|
|
||||||
return new ComponentAttributeBag([
|
|
||||||
'::value' => $attributes->get(':label'),
|
|
||||||
|
|
||||||
]);
|
|
||||||
return ':value="$label" ::value="{!!$attributes->get(":label")!!}"';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -104,8 +104,6 @@ services:
|
||||||
|
|
||||||
meilisearch:
|
meilisearch:
|
||||||
image: getmeili/meilisearch:v1.6
|
image: getmeili/meilisearch:v1.6
|
||||||
ports:
|
|
||||||
- '7700:7700'
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/meilisearch:/meili_data
|
- ./data/meilisearch:/meili_data
|
||||||
env_file:
|
env_file:
|
||||||
|
|
|
@ -2,63 +2,14 @@
|
||||||
|
|
||||||
namespace Modules\Contribution\Components;
|
namespace Modules\Contribution\Components;
|
||||||
|
|
||||||
use App\Contribution\ContributionFactory;
|
|
||||||
use App\Country;
|
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
|
|
||||||
class FillList extends Component
|
class FillList extends Component
|
||||||
{
|
{
|
||||||
|
|
||||||
public Collection $countries;
|
|
||||||
public ?int $country = null;
|
|
||||||
public Collection $compilers;
|
|
||||||
public string $eventName = '';
|
|
||||||
public string $dateFrom = '';
|
|
||||||
public string $dateUntil = '';
|
|
||||||
public string $zipLocation = '';
|
|
||||||
|
|
||||||
public function mount(): void
|
|
||||||
{
|
|
||||||
$this->countries = Country::select('name', 'id')->get();
|
|
||||||
$this->country = Country::firstWhere('name', 'Deutschland')->id;
|
|
||||||
$this->compilers = app(ContributionFactory::class)->compilerSelect();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function render()
|
public function render()
|
||||||
{
|
{
|
||||||
return <<<'HTML'
|
return <<<'HTML'
|
||||||
<x-page::layout title="Zuschüsse" menu="contribution">
|
<x-page::layout title="Zuschüsse" menu="contribution">
|
||||||
<form target="_BLANK" class="max-w-4xl w-full mx-auto gap-6 grid-cols-2 grid p-6">
|
|
||||||
<x-form::text name="event_name" wire:model="eventName" class="col-span-full" label="Veranstaltungs-Name" required></x-form::text>
|
|
||||||
<x-form::text name="date_until" wire:model="dateUntil" type="date" label="Datum bis" required></x-form::text>
|
|
||||||
<x-form::text name="date_until" wire:model="dateUntil" type="date" label="Datum bis"></x-form::text>
|
|
||||||
<x-form::text name="date_from" wire:model="dateFrom" type="date" label="Datum von" required></x-form::text>
|
|
||||||
<x-form::text name="zip_location" wire:model="zipLocation" label="PLZ / Ort" required></x-form::text>
|
|
||||||
<x-form::select id="country" wire:model="country" :options="$countries" name="country" label="Land" required></x-form::select>
|
|
||||||
|
|
||||||
<x-ui::box class="col-span-2" title="Mitglieder finden" x-data="memberSearch()">
|
|
||||||
<span x-text="JSON.stringify(members)"></span>
|
|
||||||
<div class="mt-2 grid grid-cols-[repeat(auto-fill,minmax(180px,1fr))] gap-2 col-span-2">
|
|
||||||
<x-form::text name="search_text" ref="searchInput" x-model="searchString" class="col-span-2" label="Suchen …" size="sm" @keydown.enter.prevent="onSubmitFirstMemberResult"></x-form::text>
|
|
||||||
|
|
||||||
<template x-for="member in searchHelper.getHits()" :key="member.id">
|
|
||||||
<x-form::lever
|
|
||||||
name="members"
|
|
||||||
::label="member.fullname"
|
|
||||||
::id="member.id"
|
|
||||||
::value="member.id"
|
|
||||||
size="sm"
|
|
||||||
ref="input"
|
|
||||||
x-model="members"
|
|
||||||
@keydown.enter.prevent="onSubmitMemberResult($event.target.value)"
|
|
||||||
></x-form::lever>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</x-ui::box>
|
|
||||||
|
|
||||||
<button v-for="(compiler, index) in compilers" :key="index" class="btn btn-primary mt-3 inline-block" @click.prevent="submit(compiler.class)" v-text="compiler.title"></button>
|
|
||||||
</form>
|
|
||||||
</x-page::layout>
|
</x-page::layout>
|
||||||
HTML;
|
HTML;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
namespace Modules\Contribution\Components;
|
namespace Modules\Contribution\Components;
|
||||||
|
|
||||||
use App\Contribution\Documents\RdpNrwDocument;
|
|
||||||
use App\Country;
|
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
|
@ -20,16 +18,7 @@ it('displays page', function () {
|
||||||
->assertSeeLivewire(FillList::class);
|
->assertSeeLivewire(FillList::class);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('displays fields', function () {
|
it('loads component', function () {
|
||||||
$country = Country::factory()->create(['name' => 'Deutschland']);
|
|
||||||
|
|
||||||
Livewire::test(FillList::class)
|
Livewire::test(FillList::class)
|
||||||
->assertSet('compilers.0.class', RdpNrwDocument::class)
|
->assertSee('Zuschüsse');
|
||||||
->assertSet('compilers.0.title', 'Für RdP NRW erstellen')
|
|
||||||
->assertSet('countries.0.name', 'Deutschland')
|
|
||||||
->assertSet('countries.0.id', $country->id)
|
|
||||||
->assertSet('country', $country->id)
|
|
||||||
->assertSee('Veranstaltungs-Name')
|
|
||||||
->assertSee('Datum von')
|
|
||||||
->assertSee('Deutschland');
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -39,7 +39,6 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"accounting": "^0.4.1",
|
"accounting": "^0.4.1",
|
||||||
"alpinejs-axios": "^1.0.8",
|
|
||||||
"autoprefixer": "^10.4.17",
|
"autoprefixer": "^10.4.17",
|
||||||
"axios": "^1.6.6",
|
"axios": "^1.6.6",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
|
@ -1157,12 +1156,6 @@
|
||||||
"url": "https://github.com/sponsors/epoberezkin"
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/alpinejs-axios": {
|
|
||||||
"version": "1.0.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/alpinejs-axios/-/alpinejs-axios-1.0.8.tgz",
|
|
||||||
"integrity": "sha512-6B6oxLiXvEsNUnhXT8/H8q/CPF4CThYp3s9Pw/rI/lCpiBPSBNLBuL0hgLn6VeuhLIUKL9DN3IYYWWsKWXzpKg==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/ansi-regex": {
|
"node_modules/ansi-regex": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"accounting": "^0.4.1",
|
"accounting": "^0.4.1",
|
||||||
"alpinejs-axios": "^1.0.8",
|
|
||||||
"autoprefixer": "^10.4.17",
|
"autoprefixer": "^10.4.17",
|
||||||
"axios": "^1.6.6",
|
"axios": "^1.6.6",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
|
|
|
@ -62,4 +62,22 @@ async function submit(compiler) {
|
||||||
var payload = btoa(encodeURIComponent(JSON.stringify(values.value)));
|
var payload = btoa(encodeURIComponent(JSON.stringify(values.value)));
|
||||||
window.open(`/contribution-generate?payload=${payload}`);
|
window.open(`/contribution-generate?payload=${payload}`);
|
||||||
}
|
}
|
||||||
|
function onSubmitMemberResult(selected) {
|
||||||
|
if (values.value.members.find((m) => m === selected.id) !== undefined) {
|
||||||
|
values.value.members = values.value.members.filter((m) => m !== selected.id);
|
||||||
|
} else {
|
||||||
|
values.value.members.push(selected.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSearch();
|
||||||
|
searchInput.value.$el.querySelector('input').focus();
|
||||||
|
}
|
||||||
|
function onSubmitFirstMemberResult() {
|
||||||
|
if (results.value.hits.length === 0) {
|
||||||
|
clearSearch();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmitMemberResult(results.value.hits[0]);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
import {Livewire, Alpine} from '../../vendor/livewire/livewire/dist/livewire.esm';
|
import {Livewire, Alpine} from '../../vendor/livewire/livewire/dist/livewire.esm';
|
||||||
import Tooltip from '@ryangjchandler/alpine-tooltip';
|
import Tooltip from '@ryangjchandler/alpine-tooltip';
|
||||||
|
|
||||||
import axios from 'axios';
|
|
||||||
import '../css/app.css';
|
import '../css/app.css';
|
||||||
import 'tippy.js/dist/tippy.css';
|
import 'tippy.js/dist/tippy.css';
|
||||||
import 'tippy.js/animations/shift-toward.css';
|
import 'tippy.js/animations/shift-toward.css';
|
||||||
import '../css/tooltip.css';
|
import '../css/tooltip.css';
|
||||||
import {error, success} from './toastify.js';
|
import {error, success} from './toastify.js';
|
||||||
import editor from './editor.js';
|
import editor from './editor.js';
|
||||||
import memberSearch from './memberSearch.js';
|
|
||||||
|
|
||||||
window.axios = axios;
|
|
||||||
|
|
||||||
Alpine.plugin(
|
Alpine.plugin(
|
||||||
Tooltip.defaultProps({
|
Tooltip.defaultProps({
|
||||||
|
@ -23,7 +19,6 @@ window.addEventListener('success', (event) => success(event.detail[0]));
|
||||||
|
|
||||||
document.addEventListener('alpine:init', () => {
|
document.addEventListener('alpine:init', () => {
|
||||||
Alpine.data('editor', editor);
|
Alpine.data('editor', editor);
|
||||||
Alpine.data('memberSearch', memberSearch);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Livewire.start();
|
Livewire.start();
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
import searchHelper from './searchHelper.js';
|
|
||||||
|
|
||||||
export default () => ({
|
|
||||||
members: [],
|
|
||||||
|
|
||||||
searchHelper: searchHelper([], {}),
|
|
||||||
|
|
||||||
onSubmitFirstMemberResult() {
|
|
||||||
if (this.searchHelper.hasNoHits()) {
|
|
||||||
this.searchHelper.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.onSubmitMemberResult(this.searchHelper.firstHit().id.toString());
|
|
||||||
},
|
|
||||||
|
|
||||||
onSubmitMemberResult(id) {
|
|
||||||
if (this.members.find((m) => m === id) !== undefined) {
|
|
||||||
this.members = this.members.filter((m) => m !== id);
|
|
||||||
} else {
|
|
||||||
this.members.push(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.searchHelper.clear();
|
|
||||||
this.$root.querySelector('input').focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
set searchString(v) {
|
|
||||||
this.searchHelper.setInput(v);
|
|
||||||
},
|
|
||||||
|
|
||||||
get searchString() {
|
|
||||||
return this.searchHelper.getInput();
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,58 +0,0 @@
|
||||||
export default (params = [], options = {}) => ({
|
|
||||||
params: params,
|
|
||||||
options: options,
|
|
||||||
results: {
|
|
||||||
hits: [],
|
|
||||||
},
|
|
||||||
realSearchString: '',
|
|
||||||
|
|
||||||
async search(text, filters = [], options = {}) {
|
|
||||||
var response = await axios.post(
|
|
||||||
import.meta.env.MODE === 'development' ? 'http://localhost:7700/indexes/members/search' : '/indexes/members/search',
|
|
||||||
{
|
|
||||||
q: text,
|
|
||||||
filter: filters,
|
|
||||||
sort: ['lastname:asc', 'firstname:asc'],
|
|
||||||
...options,
|
|
||||||
},
|
|
||||||
{headers: {Authorization: 'Bearer ' + document.querySelector('meta[name="meilisearch_key"]').content}}
|
|
||||||
);
|
|
||||||
|
|
||||||
return response.data;
|
|
||||||
},
|
|
||||||
|
|
||||||
async setInput(v) {
|
|
||||||
this.realSearchString = v;
|
|
||||||
|
|
||||||
if (!v.length) {
|
|
||||||
this.results = {hits: []};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.results = await this.search(v, this.params, this.options);
|
|
||||||
},
|
|
||||||
|
|
||||||
getInput() {
|
|
||||||
return this.realSearchString;
|
|
||||||
},
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
this.setInput('');
|
|
||||||
},
|
|
||||||
|
|
||||||
getHits() {
|
|
||||||
return this.results.hits;
|
|
||||||
},
|
|
||||||
|
|
||||||
hasHits() {
|
|
||||||
return this.results.hits.length > 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
hasNoHits() {
|
|
||||||
return !this.hasHits();
|
|
||||||
},
|
|
||||||
|
|
||||||
firstHit() {
|
|
||||||
return this.results.hits[0];
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -103,6 +103,7 @@ Route::group(['middleware' => 'auth:web'], function (): void {
|
||||||
Route::post('/api/member/search', SearchAction::class)->name('member.search');
|
Route::post('/api/member/search', SearchAction::class)->name('member.search');
|
||||||
|
|
||||||
// ------------------------------- Contributions -------------------------------
|
// ------------------------------- Contributions -------------------------------
|
||||||
|
Route::get('/contribution', ContributionFormAction::class)->name('contribution.form');
|
||||||
Route::get('/contribution-generate', ContributionGenerateAction::class)->name('contribution.generate');
|
Route::get('/contribution-generate', ContributionGenerateAction::class)->name('contribution.generate');
|
||||||
Route::post('/contribution-validate', ContributionValidateAction::class)->name('contribution.validate');
|
Route::post('/contribution-validate', ContributionValidateAction::class)->name('contribution.validate');
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature\Contribution;
|
||||||
|
|
||||||
|
use App\Contribution\Documents\RdpNrwDocument;
|
||||||
|
use App\Country;
|
||||||
|
use App\Member\Member;
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class IndexTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseTransactions;
|
||||||
|
|
||||||
|
public function testItHasContributionIndex(): void
|
||||||
|
{
|
||||||
|
$this->withoutExceptionHandling()->login()->loginNami();
|
||||||
|
$country = Country::factory()->create(['name' => 'Deutschland']);
|
||||||
|
Member::factory()->defaults()->create(['firstname' => 'Max', 'lastname' => 'Muster']);
|
||||||
|
Member::factory()->defaults()->create(['firstname' => 'Jane', 'lastname' => 'Muster']);
|
||||||
|
|
||||||
|
$response = $this->get('/contribution');
|
||||||
|
|
||||||
|
$this->assertInertiaHas([
|
||||||
|
'class' => RdpNrwDocument::class,
|
||||||
|
'title' => 'Für RdP NRW erstellen',
|
||||||
|
], $response, 'compilers.0');
|
||||||
|
$this->assertInertiaHas([
|
||||||
|
'id' => $country->id,
|
||||||
|
'name' => $country->name,
|
||||||
|
], $response, 'countries.0');
|
||||||
|
$this->assertInertiaHas([
|
||||||
|
'country' => $country->id,
|
||||||
|
], $response, 'data');
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Tests\Unit\View\Form;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Blade;
|
|
||||||
use Tests\TestCase;
|
|
||||||
|
|
||||||
uses(TestCase::class);
|
|
||||||
|
|
||||||
it('renders component', function ($component, $params, $expected = '', $notExpected = '') {
|
|
||||||
$rendered = Blade::render($component, $params);
|
|
||||||
|
|
||||||
if ($expected) {
|
|
||||||
expect($rendered)->toContain($expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($notExpected) {
|
|
||||||
expect($rendered)->not()->toContain($notExpected);
|
|
||||||
}
|
|
||||||
})->with([
|
|
||||||
'component parameter' => ['<x-form::label :value="$label" />', ['label' => 'the label'], 'x-text="`the label`"'],
|
|
||||||
'component parameter with double quotes' => ['<x-form::label :value="$label" />', ['label' => 'the "label"'], 'x-text="`the "label"`"'],
|
|
||||||
'component parameter with ``' => ['<x-form::label value="the `label`" />', [], 'x-text="`the \\`label\\``"'],
|
|
||||||
'escape dollars' => ['<x-form::label value="the $label" />', [], 'x-text="`the \\$label`"'],
|
|
||||||
'escape kl' => ['<x-form::label value="the {label}" />', [], 'x-text="`the \\{label\\}`"'],
|
|
||||||
'raw php string' => ['<x-form::label value="the label" />', [], 'x-text="`the label`"'],
|
|
||||||
'raw js string' => ['<x-form::label ::value="theLabel" />', [], 'x-text="theLabel"'],
|
|
||||||
'raw js string with tag' => ['<x-form::label ::value="the<Label" />', [], 'x-text="the<Label"'],
|
|
||||||
'raw js string empty' => ['<x-form::label value="lala" ::value="" />', [], 'x-text="`lala`"'],
|
|
||||||
'renders required' => ['<x-form::label value="" required/>', [], 'x-if="true"'],
|
|
||||||
'renders required' => ['<x-form::label value="" />', [], 'x-if="false"'],
|
|
||||||
]);
|
|
|
@ -1,31 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Tests\Unit\View\Form;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Blade;
|
|
||||||
use Illuminate\Support\Facades\View;
|
|
||||||
use Illuminate\Support\ViewErrorBag;
|
|
||||||
use Tests\TestCase;
|
|
||||||
|
|
||||||
uses(TestCase::class);
|
|
||||||
|
|
||||||
it('renders component', function ($component, $params, $expected = '', $notExpected = '') {
|
|
||||||
View::share(['errors' => new ViewErrorBag()]);
|
|
||||||
$rendered = Blade::render($component, $params);
|
|
||||||
|
|
||||||
if ($expected) {
|
|
||||||
expect($rendered)->toContain($expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($notExpected) {
|
|
||||||
expect($rendered)->not()->toContain($notExpected);
|
|
||||||
}
|
|
||||||
})->with([
|
|
||||||
'php string' => ['<x-form::lever name="name" label="the label" />', [], 'x-text="`the label`"'],
|
|
||||||
'php string with escaping' => ['<x-form::lever name="name" label="the <label>" />', [], 'x-text="`the <label>`"'],
|
|
||||||
'php string with var' => ['<x-form::lever name="name" :label="$label" />', ['label' => 'the <label>'], 'x-text="`the <label>`"'],
|
|
||||||
'js plain string' => ['<x-form::lever name="name" ::label="post.name" />', [], 'x-text="post.name"'],
|
|
||||||
'js plain string with <' => ['<x-form::lever name="name" ::label="post.<name" />', [], 'x-text="post.<name"'],
|
|
||||||
'raw id' => ['<x-form::lever name="name" ::id="post.id" />', [], ':id="post.id"'],
|
|
||||||
'raw id with for' => ['<x-form::lever name="name" ::id="post.id" />', [], ':for="post.id"'],
|
|
||||||
]);
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Tests\Unit\View\Form;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Blade;
|
|
||||||
use Illuminate\Support\Facades\View;
|
|
||||||
use Illuminate\Support\ViewErrorBag;
|
|
||||||
use Tests\TestCase;
|
|
||||||
|
|
||||||
uses(TestCase::class);
|
|
||||||
|
|
||||||
it('renders component', function ($component, $params, $expected) {
|
|
||||||
View::share(['errors' => new ViewErrorBag()]);
|
|
||||||
$rendered = Blade::render($component, $params);
|
|
||||||
|
|
||||||
dd($rendered);
|
|
||||||
expect($rendered)->toContain($expected);
|
|
||||||
})->with([
|
|
||||||
'php string' => ['<x-form::text name="name" label="the label" />', [], 'x-text="`the label`"'],
|
|
||||||
// 'php string with escaping' => ['<x-form::text name="name" label="the <label>" />', [], 'x-text="`the <label>`"'],
|
|
||||||
// 'php string with var' => ['<x-form::text name="name" :label="$label" />', ['label' => 'the <label>'], 'x-text="`the <label>`"'],
|
|
||||||
// 'js plain string' => ['<x-form::text name="name" ::label="post.name" />', [], 'x-text="post.name"'],
|
|
||||||
// 'js plain string with <' => ['<x-form::text name="name" ::label="post.<name" />', [], 'x-text="post.<name"'],
|
|
||||||
// 'raw id' => ['<x-form::text name="name" ::id="post.id" />', [], ':id="post.id"'],
|
|
||||||
// 'raw id with for' => ['<x-form::text name="name" ::id="post.id" />', [], ' :for="post.id"'],
|
|
||||||
]);
|
|
Loading…
Reference in New Issue