🚀 Integrate Flux modals and toasts into Blade templates, refactor delete confirmation logic, and replace deprecated WireUI notifications for improved UX.

This commit is contained in:
HolgerHatGarKeineNode
2026-01-18 20:47:12 +01:00
parent b090336c4f
commit 18f8dd99e3
6 changed files with 127 additions and 128 deletions

View File

@@ -89,14 +89,15 @@
($currentPleb && $currentPleb->id === $project->einundzwanzig_pleb_id)
|| ($currentPleb && in_array($currentPleb->npub, config('einundzwanzig.config.current_board'), true))
)
<flux:button
icon="trash"
xs
negative
wire:click="confirmDelete({{ $project->id }})"
wire:loading.attr="disabled">
Löschen
</flux:button>
<flux:modal.trigger name="delete-project">
<flux:button
icon="trash"
xs
negative
wire:loading.attr="disabled">
Löschen
</flux:button>
</flux:modal.trigger>
<flux:button
icon="pencil"
xs

View File

@@ -120,6 +120,10 @@
{{ $slot }}
</flux:main>
@persist('toast')
<flux:toast />
@endpersist
@fluxScripts
@livewireScriptConfig
<script>

View File

@@ -517,8 +517,6 @@ new class extends Component {
Wahl des Präsidiums
</h1>
<div class="grid sm:grid-cols-2 gap-6">
<div
<div class="grid sm:grid-cols-2 gap-6">
<flux:card>
<header>
<div class="flex items-center justify-between">
@@ -565,12 +563,10 @@ new class extends Component {
</flux:card>
</div>
<h1 class="mt-6 text-xl leading-snug text-gray-800 dark:text-gray-100 font-bold mb-1 sm:mb-0 ml-2">
<h1 class="mt-6 text-xl leading-snug text-gray-800 dark:text-gray-100 font-bold mb-1 sm:mb-0 ml-2">
Wahl der übrigen Vorstandsmitglieder
</h1>
<div class="grid gap-6">
<div
<flux:card>
<div class="flex flex-col h-full p-5">
<div class="grow mt-2">
@@ -744,6 +740,7 @@ new class extends Component {
</div>
</div>
</div>
@endif
</div>

View File

@@ -160,9 +160,7 @@ class extends Component {
<div class="space-y-2">
@forelse($news as $post)
<article wire:key="post_{{ $post->id }}"
<article wire:key="post_{{ $post->id }}"
<flux:card>
<flux:card wire:key="post_{{ $post->id }}">
<!-- Avatar -->
<div class="shrink-0 mt-1.5">
<img class="w-8 h-8 rounded-full"

View File

@@ -4,6 +4,7 @@ use App\Enums\AssociationStatus;
use App\Livewire\Forms\ApplicationForm;
use App\Models\EinundzwanzigPleb;
use App\Support\NostrAuth;
use Flux\Flux;
use Livewire\Component;
use swentel\nostr\Event\Event as NostrEvent;
use swentel\nostr\Filter\Filter;
@@ -14,7 +15,6 @@ use swentel\nostr\Relay\RelaySet;
use swentel\nostr\Request\Request;
use swentel\nostr\Sign\Sign;
use swentel\nostr\Subscription\Subscription;
use WireUi\Actions\Notification;
new class extends Component {
public ApplicationForm $form;
@@ -132,8 +132,7 @@ new class extends Component {
$this->currentPleb->update([
'email' => $this->email,
]);
$notification = new Notification($this);
$notification->success('E-Mail Adresse gespeichert.');
Flux::toast('E-Mail Adresse gespeichert.');
}
public function pay($comment): \Illuminate\Http\RedirectResponse
@@ -175,9 +174,9 @@ new class extends Component {
return redirect($response->json()['checkoutLink']);
} catch (\Exception $e) {
$notification = new Notification($this);
$notification->error(
Flux::toast(
'Fehler beim Erstellen der Rechnung. Bitte versuche es später erneut: '.$e->getMessage(),
variant: 'danger',
);
return redirect()->route('association.profile');
@@ -319,7 +318,7 @@ new class extends Component {
</div>
<flux:card mb-8>
<flux:card>
<div class="flex flex-col md:flex-row md:-mr-px">
<!-- Sidebar -->
@@ -340,7 +339,7 @@ new class extends Component {
</a>
</li>
</ul>
</flux:card>
</div>
<!-- Panel -->
<div class="grow">
@@ -349,7 +348,7 @@ new class extends Component {
<div class="p-6 space-y-6">
<h2 class="sm:text-2xl text-[#1B1B1B] dark:text-gray-100 font-bold mb-5">Aktueller Status</h2>
<section>
<section>
@if(!$currentPleb)
<div class="space-y-2 mb-12">
@@ -432,8 +431,6 @@ new class extends Component {
</div>
</flux:card>
<flux:card>
<div
class="md:flex justify-between items-center space-y-4 md:space-y-0 space-x-2">
<!-- Left side -->
<div class="flex items-start space-x-3 md:space-x-4">
<div>
@@ -453,12 +450,10 @@ new class extends Component {
Browser Firefox
</div>
</div>
</flux:card>
</div>
</div>
@endif
</flux:card>
@endif
<div class="flex flex-wrap space-y-2 sm:space-y-0 items-center justify-between">
<div class="flex flex-wrap space-y-2 sm:space-y-0 items-center justify-between">
<template x-if="$store.nostr.user">
<div class="flex items">
<img class="w-12 h-12 rounded-full"
@@ -473,10 +468,8 @@ new class extends Component {
</div>
</div>
</template>
@if($currentPubkey && $currentPleb->association_status->value < 2)
<div
@if($currentPubkey && $currentPleb->association_status->value < 2)
<flux:card>
<div class="flex w-full justify-between items-start">
<div class="flex">
<svg class="shrink-0 fill-current text-green-500 mt-[3px] mr-3"
width="16" height="16" viewBox="0 0 16 16">
@@ -486,13 +479,12 @@ new class extends Component {
<div>Profil in der Datenbank vorhanden.</div>
</div>
</flux:card>
</div>
@endif
</div>
</div>
@endif
</div>
</section>
<section>
@if($currentPubkey && !$currentPleb->application_for && $currentPleb->association_status->value < 2)
<section>
<h3 class="text-xl leading-snug text-[#1B1B1B] dark:text-gray-100 font-bold mb-1">
Einundzwanzig Mitglied werden
</h3>
@@ -518,11 +510,9 @@ new class extends Component {
<flux:button wire:click="save({{ AssociationStatus::PASSIVE() }})">
Mit deinem aktuellen Nostr-Profil Mitglied werden
</flux:button>
</div>
</div>
@endif
@if($currentPubkey)
<div
</div>
</div>
@if($currentPubkey)
<flux:card class="mt-6">
<div class="flex w-full justify-between items-start">
<div class="flex w-full">
@@ -570,22 +560,26 @@ new class extends Component {
<flux:error name="email" />
</flux:field>
</div>
<div wire:key="showSave" class="flex space-x-2 mt-2">
<div wire:key="showSave" class="flex space-x-2 mt-2">
<flux:button wire:click="saveEmail" wire:loading.attr="disabled">
Speichern
</flux:button>
</div>
@endif
</div>
</flux:card>
</div>
</div>
</div>
</div>
</div>
@endif
@endif
</div>
@endif
</section>
</div>
@endif
</section>
<section>
@if($currentPleb && $currentPleb->association_status->value > 1)
<div class="flex flex-col space-y-4">
<section>
@if($currentPleb && $currentPleb->association_status->value > 1)
<div class="flex flex-col space-y-4">
<div
<flux:card class="max-w-lg">
<div class="flex w-full justify-between items-start">
@@ -603,14 +597,13 @@ new class extends Component {
</div>
</div>
</div>
</flux:card>
</div>
@endif
</section>
</flux:card>
</div>
@endif
</section>
<section>
<section>
@if($currentPleb && $currentPleb->association_status->value > 1)
<div
<flux:card>
<div class="flex w-full justify-between items-start">
<div class="flex">
@@ -626,47 +619,36 @@ new class extends Component {
Mitgliedsbeitrags: <span
class="break-all">{{ $currentPleb->paymentEvents->last()->event_id }}</span>
</p>
<div>
@php
// latest event by created_at field of $events
$latestEvent = collect($events)->sortByDesc('created_at')->first();
@endphp
@if(isset($latestEvent))
<div>
@if(isset($latestEvent))
<p>{{ $latestEvent['content'] }}</p>
<div class="mt-8">
@if(!$currentYearIsPaid)
<div class="flex justify-center">
<button
wire:click="pay('{{ date('Y') }}:{{ $currentPubkey }}')"
class="btn text-2xl dark:bg-gray-800 border-gray-200 dark:border-gray-700/60 hover:border-gray-300 dark:hover:border-gray-600 text-green-500"
>
<flux:button wire:click="pay('{{ date('Y') }}:{{ $currentPubkey }}')" class="text-2xl">
<i class="fa-sharp-duotone fa-solid fa-bolt-lightning mr-2"></i>
Pay {{ $amountToPay }} Sats
</button>
</flux:button>
</div>
@else
@if($currentYearIsPaid)
<div class="flex sm:justify-center">
<div
class="btn sm:text-2xl dark:bg-gray-800 border-gray-200 dark:border-gray-700/60 text-green-500"
>
<flux:button disabled class="sm:text-2xl">
<i class="fa-sharp-duotone fa-solid fa-check-circle mr-2"></i>
aktuelles Jahr bezahlt
</div>
</flux:button>
</div>
@endif
@endif
</div>
@else
<div class="flex sm:justify-center">
<button
class="btn dark:bg-gray-800 border-gray-200 dark:border-gray-700/60 hover:border-gray-300 dark:hover:border-gray-600 text-amber-500"
>
<flux:button disabled>
<i class="fa-sharp-duotone fa-solid fa-user-helmet-safety mr-2"></i>
Unser Nostr-Relay konnte derzeit nicht erreicht
werden, um eine Zahlung zu initialisieren. Bitte
versuche es später noch einmal.
</button>
</flux:button>
</div>
@endif
</div>
@@ -693,49 +675,49 @@ new class extends Component {
</th>
</tr>
</thead>
<!-- Table body -->
<tbody class="text-sm">
@foreach($payments as $payment)
<tr class="flex flex-wrap md:table-row md:flex-no-wrap border-b border-gray-200 dark:border-gray-700/60 py-2 md:py-0">
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
<div
class="text-left font-medium text-gray-800 dark:text-gray-100">
<span class="sm:hidden">Sats:</span>
{{ $payment->amount }}
</div>
</td>
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
<div
class="text-left"><span
class="sm:hidden">Jahr:</span>{{ $payment->year }}
</div>
</td>
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
<div
class="text-left font-medium break-all">{{ $payment->event_id }}</div>
</td>
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
@if($payment->btc_pay_invoice)
<flux:button href="https://pay.einundzwanzig.space/i/{{ $payment->btc_pay_invoice }}/receipt"
target="_blank"
size="xs"
variant="subtle">
Quittung
</flux:button>
@endif
</td>
</tr>
@endforeach
</tbody>
<!-- Table body -->
<tbody class="text-sm">
@foreach($payments as $payment)
<tr class="flex flex-wrap md:table-row md:flex-no-wrap border-b border-gray-200 dark:border-gray-700/60 py-2 md:py-0">
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
<div
class="text-left font-medium text-gray-800 dark:text-gray-100">
<span class="sm:hidden">Sats:</span>
{{ $payment->amount }}
</div>
</td>
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
<div
class="text-left"><span
class="sm:hidden">Jahr:</span>{{ $payment->year }}
</div>
</td>
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
<div
class="text-left font-medium break-all">{{ $payment->event_id }}</div>
</td>
<td class="w-full block md:w-auto md:table-cell py-0.5 md:py-2">
@if($payment->btc_pay_invoice)
<flux:button href="https://pay.einundzwanzig.space/i/{{ $payment->btc_pay_invoice }}/receipt"
target="_blank"
size="xs"
variant="subtle">
Quittung
</flux:button>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</section>
</div>
</div>
</div>
</div>
</flux:card>
@endif
</section>
</flux:card>
@endif
</section>
</div>
@@ -743,6 +725,7 @@ new class extends Component {
</div>
</div>
</div>
</div>
</div>

View File

@@ -2,12 +2,14 @@
use App\Models\ProjectProposal;
use App\Support\NostrAuth;
use Flux\Flux;
use Livewire\Component;
use WireUi\Actions\Notification;
new class extends Component {
public string $activeFilter = 'all';
public ?string $confirmDeleteId = null;
public string $search = '';
public \Illuminate\Database\Eloquent\Collection $projects;
@@ -74,16 +76,8 @@ new class extends Component {
public function confirmDelete($id): void
{
$notification = new Notification($this);
$notification->confirm([
'title' => 'Projektunterstützung löschen',
'message' => 'Bist du sicher, dass du diese Projektunterstützung löschen möchtest?',
'accept' => [
'label' => 'Ja, löschen',
'method' => 'delete',
'params' => $id,
],
]);
$this->confirmDeleteId = $id;
Flux::modal('delete-project')->show();
}
public function setFilter($filter): void
@@ -91,10 +85,12 @@ new class extends Component {
$this->activeFilter = $filter;
}
public function delete($id): void
public function delete(): void
{
ProjectProposal::query()->findOrFail($id)->delete();
ProjectProposal::query()->findOrFail($this->confirmDeleteId)->delete();
Flux::toast('Projektunterstützung gelöscht.');
$this->loadProjects();
Flux::modals()->close();
}
};
@@ -170,5 +166,25 @@ new class extends Component {
@endforeach
</div>
<!-- Confirmation modal -->
<flux:modal name="delete-project" class="min-w-[22rem]">
<div class="space-y-6">
<div>
<flux:heading size="lg">Projektunterstützung löschen</flux:heading>
<flux:text class="mt-2">
<p>Bist du sicher, dass du diese Projektunterstützung löschen möchtest?</p>
<p>Diese Aktion kann nicht rückgängig gemacht werden.</p>
</flux:text>
</div>
<div class="flex gap-2">
<flux:spacer />
<flux:modal.close>
<flux:button variant="ghost">Abbrechen</flux:button>
</flux:modal.close>
<flux:button type="submit" wire:click="delete" variant="danger">Ja, löschen</flux:button>
</div>
</div>
</flux:modal>
</div>
</div>