mirror of
https://github.com/HolgerHatGarKeineNode/einundzwanzig-nostr.git
synced 2025-12-13 05:26:47 +00:00
Updated the zapEndpoint URL in the nostrZap.js file to direct towards the updated URL. Additionally, removed an unused function from the profile.blade.php file for cleaner code.
553 lines
32 KiB
PHP
553 lines
32 KiB
PHP
<?php
|
|
|
|
use Livewire\Volt\Component;
|
|
|
|
use SimpleSoftwareIO\QrCode\Facades\QrCode;
|
|
use swentel\nostr\Filter\Filter;
|
|
use swentel\nostr\Key\Key;
|
|
use swentel\nostr\Message\EventMessage;
|
|
use swentel\nostr\Message\RequestMessage;
|
|
use swentel\nostr\Relay\Relay;
|
|
use swentel\nostr\Relay\RelaySet;
|
|
use swentel\nostr\Request\Request;
|
|
use swentel\nostr\Subscription\Subscription;
|
|
use swentel\nostr\Event\Event as NostrEvent;
|
|
use swentel\nostr\Sign\Sign;
|
|
|
|
use function Livewire\Volt\computed;
|
|
use function Livewire\Volt\mount;
|
|
use function Livewire\Volt\state;
|
|
use function Livewire\Volt\with;
|
|
use function Laravel\Folio\{middleware};
|
|
use function Laravel\Folio\name;
|
|
use function Livewire\Volt\{on, form, updated};
|
|
|
|
name('association.profile');
|
|
|
|
state(['yearsPaid' => []]);
|
|
state(['events' => []]);
|
|
state(['payments' => []]);
|
|
state(['invoice' => null]);
|
|
state(['qrCode' => null]);
|
|
state(['amountToPay' => 21]);
|
|
state(['currentYearIsPaid' => false]);
|
|
state(['currentPubkey' => null]);
|
|
state(['currentPleb' => null]);
|
|
|
|
form(\App\Livewire\Forms\ApplicationForm::class);
|
|
|
|
updated([
|
|
'invoice' => function () {
|
|
$this->qrCode = base64_encode(
|
|
QrCode::format('png')
|
|
->size(300)
|
|
->merge('/public/android-chrome-192x192.png', .3)
|
|
->errorCorrection('H')
|
|
->generate($this->invoice),
|
|
);
|
|
},
|
|
]);
|
|
|
|
on([
|
|
'nostrLoggedIn' => function ($pubkey) {
|
|
$this->currentPubkey = $pubkey;
|
|
$this->currentPleb = \App\Models\EinundzwanzigPleb::query()
|
|
->with([
|
|
'paymentEvents' => fn($query)
|
|
=> $query->where('year', date('Y')),
|
|
])
|
|
->where('pubkey', $pubkey)->first();
|
|
if ($this->currentPleb->association_status === \App\Enums\AssociationStatus::ACTIVE) {
|
|
$this->amountToPay = 21;
|
|
}
|
|
if ($this->currentPleb->paymentEvents->count() < 1) {
|
|
$this->createPaymentEvent();
|
|
$this->currentPleb->load('paymentEvents');
|
|
}
|
|
$this->loadEvents();
|
|
$this->searchPaymentEvent();
|
|
},
|
|
]);
|
|
|
|
$listenForPayment = function () {
|
|
if (!$this->currentYearIsPaid) {
|
|
$this->searchPaymentEvent();
|
|
}
|
|
};
|
|
|
|
$searchPaymentEvent = function () {
|
|
$subscription = new Subscription();
|
|
$subscriptionId = $subscription->setId();
|
|
|
|
$filter1 = new Filter();
|
|
$filter1->setKinds([9735]);
|
|
$filters = [$filter1];
|
|
|
|
$requestMessage = new RequestMessage($subscriptionId, $filters);
|
|
|
|
$relays = [
|
|
new Relay(config('services.relay')),
|
|
];
|
|
$relaySet = new RelaySet();
|
|
$relaySet->setRelays($relays);
|
|
|
|
$request = new Request($relaySet, $requestMessage);
|
|
$response = $request->send();
|
|
|
|
if (count($response[config('services.relay')]) > 0) {
|
|
$this->payments = collect($response[config('services.relay')])
|
|
->map(fn($event)
|
|
=> [
|
|
'id' => $event->event->id,
|
|
'kind' => $event->event->kind,
|
|
'content' => $event->event->content,
|
|
'pubkey' => $event->event->pubkey,
|
|
'tags' => $event->event->tags,
|
|
'created_at' => $event->event->created_at,
|
|
])
|
|
->filter(fn($payment)
|
|
=> collect($payment['tags'])->firstWhere('0', 'p')[1] === $this->currentPubkey
|
|
&& json_decode(
|
|
collect($payment['tags'])->firstWhere('0', 'description')[1],
|
|
true,
|
|
512,
|
|
JSON_THROW_ON_ERROR,
|
|
)['content'] == date('Y'))
|
|
->values()
|
|
->toArray();
|
|
|
|
$this->yearsPaid = collect($this->payments)->map(fn($payment)
|
|
=> [
|
|
'year' => $payment['content'],
|
|
'amount' => collect(
|
|
json_decode(
|
|
collect($payment['tags'])->firstWhere('0', 'description')[1],
|
|
true,
|
|
512,
|
|
JSON_THROW_ON_ERROR,
|
|
)['tags'],
|
|
)->firstWhere('0', 'amount')[1] / 1000,
|
|
]);
|
|
|
|
$this->currentYearIsPaid = collect($this->yearsPaid)->contains(
|
|
fn($yearPaid) => $yearPaid['year'] == date('Y') && $yearPaid['amount'] == $this->amountToPay,
|
|
);
|
|
|
|
if ($this->currentYearIsPaid) {
|
|
$this->qrCode = null;
|
|
$this->currentPleb->paymentEvents->first()->update(['paid' => true]);
|
|
}
|
|
}
|
|
};
|
|
|
|
$save = function ($type) {
|
|
$this->form->validate();
|
|
$this->currentPleb
|
|
->update([
|
|
'application_for' => $type,
|
|
'application_text' => $this->form->reason,
|
|
]);
|
|
};
|
|
|
|
$createPaymentEvent = function () {
|
|
$note = new NostrEvent();
|
|
$note->setKind(32121);
|
|
$note->setContent(
|
|
'Dieses Event dient der Zahlung des Mitgliedsbeitrags für das Jahr ' . date(
|
|
'Y',
|
|
) . '. Bitte zappe den Betrag von ' . $this->amountToPay . ' Satoshi.',
|
|
);
|
|
$note->setTags([
|
|
['d', $this->currentPleb->pubkey . ',' . date('Y')],
|
|
['zap', 'daf83d92768b5d0005373f83e30d4203c0b747c170449e02fea611a0da125ee6', config('services.relay'), '1'],
|
|
]);
|
|
$signer = new Sign();
|
|
$signer->signEvent($note, config('services.nostr'));
|
|
|
|
$eventMessage = new EventMessage($note);
|
|
|
|
$relayUrl = config('services.relay');
|
|
$relay = new Relay($relayUrl);
|
|
$relay->setMessage($eventMessage);
|
|
$result = $relay->send();
|
|
|
|
$this->currentPleb->paymentEvents()->create([
|
|
'year' => date('Y'),
|
|
'event_id' => $result->eventId,
|
|
'amount' => $this->amountToPay,
|
|
]);
|
|
};
|
|
|
|
$loadEvents = function () {
|
|
$subscription = new Subscription();
|
|
$subscriptionId = $subscription->setId();
|
|
|
|
$filter1 = new Filter();
|
|
$filter1->setKinds([32121]);
|
|
$filter1->setAuthors(['daf83d92768b5d0005373f83e30d4203c0b747c170449e02fea611a0da125ee6']);
|
|
$filters = [$filter1];
|
|
|
|
$requestMessage = new RequestMessage($subscriptionId, $filters);
|
|
|
|
$relays = [
|
|
new Relay(config('services.relay')),
|
|
];
|
|
$relaySet = new RelaySet();
|
|
$relaySet->setRelays($relays);
|
|
|
|
$request = new Request($relaySet, $requestMessage);
|
|
$response = $request->send();
|
|
|
|
$this->events = collect($response[config('services.relay')])
|
|
->map(fn($event)
|
|
=> [
|
|
'id' => $event->event->id,
|
|
'kind' => $event->event->kind,
|
|
'content' => $event->event->content,
|
|
'pubkey' => $event->event->pubkey,
|
|
'tags' => $event->event->tags,
|
|
'created_at' => $event->event->created_at,
|
|
])
|
|
->unique('id')
|
|
->toArray();
|
|
};
|
|
|
|
?>
|
|
|
|
<x-layouts.app title="{{ __('Wahl') }}">
|
|
@volt
|
|
<div class="px-4 sm:px-6 lg:px-8 py-8 w-full max-w-9xl mx-auto" x-data="nostrZap(@this)">
|
|
|
|
<!-- Page header -->
|
|
<div class="mb-8">
|
|
|
|
<!-- Title -->
|
|
<h1 class="text-2xl md:text-3xl text-[#1B1B1B] dark:text-gray-100 font-bold">
|
|
Einundzwanzig ist, was du draus machst
|
|
</h1>
|
|
|
|
</div>
|
|
|
|
<div class="bg-white dark:bg-[#1B1B1B] shadow-sm rounded-xl mb-8">
|
|
<div class="flex flex-col md:flex-row md:-mr-px">
|
|
|
|
<!-- Sidebar -->
|
|
<div
|
|
class="flex flex-nowrap overflow-x-scroll no-scrollbar md:block md:overflow-auto px-3 py-6 border-b md:border-b-0 md:border-r border-gray-200 dark:border-gray-700/60 min-w-60 md:space-y-3">
|
|
<!-- Group 1 -->
|
|
<div>
|
|
<div class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase mb-3">
|
|
Meine Mitgliedschaft
|
|
</div>
|
|
<ul class="flex flex-nowrap md:block mr-3 md:mr-0">
|
|
<li class="mr-0.5 md:mr-0 md:mb-0.5">
|
|
<a class="flex items-center px-2.5 py-2 rounded-lg whitespace-nowrap bg-[linear-gradient(135deg,var(--tw-gradient-stops))] from-orange-500/[0.12] dark:from-orange-500/[0.24] to-orange-500/[0.04]"
|
|
href="#0">
|
|
<i class="fa-sharp-duotone fa-solid fa-id-card-clip shrink-0 fill-current text-orange-400 mr-2"></i>
|
|
<span
|
|
class="text-sm font-medium text-orange-500 dark:text-orange-400">Status</span>
|
|
</a>
|
|
</li>
|
|
{{--<li class="mr-0.5 md:mr-0 md:mb-0.5">
|
|
<a class="flex items-center px-2.5 py-2 rounded-lg whitespace-nowrap"
|
|
href="notifications.html">
|
|
<svg class="shrink-0 fill-current text-gray-400 dark:text-gray-500 mr-2" width="16"
|
|
height="16" viewBox="0 0 16 16">
|
|
<path
|
|
d="m9 12.614 4.806 1.374a.15.15 0 0 0 .174-.21L8.133 2.082a.15.15 0 0 0-.268 0L2.02 13.777a.149.149 0 0 0 .174.21L7 12.614V9a1 1 0 1 1 2 0v3.614Zm-1 1.794-5.257 1.503c-1.798.514-3.35-1.355-2.513-3.028L6.076 1.188c.791-1.584 3.052-1.584 3.845 0l5.848 11.695c.836 1.672-.714 3.54-2.512 3.028L8 14.408Z"/>
|
|
</svg>
|
|
<span
|
|
class="text-sm font-medium text-gray-600 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-200">My Notifications</span>
|
|
</a>
|
|
</li>--}}
|
|
</ul>
|
|
</div>
|
|
<!-- Group 2 -->
|
|
{{--<div>
|
|
<div class="text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase mb-3">Experience
|
|
</div>
|
|
<ul class="flex flex-nowrap md:block mr-3 md:mr-0">
|
|
<li class="mr-0.5 md:mr-0 md:mb-0.5">
|
|
<a class="flex items-center px-2.5 py-2 rounded-lg whitespace-nowrap"
|
|
href="feedback.html">
|
|
<svg class="shrink-0 fill-current text-gray-400 dark:text-gray-500 mr-2" width="16"
|
|
height="16" viewBox="0 0 16 16">
|
|
<path
|
|
d="M14.3.3c.4-.4 1-.4 1.4 0 .4.4.4 1 0 1.4l-8 8c-.2.2-.4.3-.7.3-.3 0-.5-.1-.7-.3-.4-.4-.4-1 0-1.4l8-8zM15 7c.6 0 1 .4 1 1 0 4.4-3.6 8-8 8s-8-3.6-8-8 3.6-8 8-8c.6 0 1 .4 1 1s-.4 1-1 1C4.7 2 2 4.7 2 8s2.7 6 6 6 6-2.7 6-6c0-.6.4-1 1-1z"/>
|
|
</svg>
|
|
<span
|
|
class="text-sm font-medium text-gray-600 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-200">Give Feedback</span>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>--}}
|
|
</div>
|
|
|
|
<!-- Panel -->
|
|
<div class="grow">
|
|
|
|
<!-- Panel body -->
|
|
<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>
|
|
|
|
<!-- Picture -->
|
|
<section>
|
|
<div class="flex flex-wrap space-y-2 sm:space-y-0 items-center justify-between">
|
|
<x-button label="Mit Nostr verbinden" @click="openNostrLogin"
|
|
x-show="!$store.nostr.user"/>
|
|
<template x-if="$store.nostr.user">
|
|
<div class="flex items">
|
|
<img class="w-12 h-12 rounded-full"
|
|
x-bind:src="$store.nostr.user.picture"
|
|
alt="">
|
|
<div class="ml-4">
|
|
<h3 class="w-48 sm:w-full truncate text-lg leading-snug text-[#1B1B1B] dark:text-gray-100 font-bold"
|
|
x-text="$store.nostr.user.display_name"></h3>
|
|
<div
|
|
class="w-48 sm:w-full truncate text-sm text-gray-500 dark:text-gray-400"
|
|
x-text="$store.nostr.user.name"></div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
@if($currentPubkey && $currentPleb->association_status->value < 2)
|
|
<div
|
|
class="inline-flex min-w-80 px-4 py-2 rounded-lg text-sm bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700/60 text-gray-600 dark:text-gray-100">
|
|
<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">
|
|
<path
|
|
d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zM7 11.4L3.6 8 5 6.6l2 2 4-4L12.4 6 7 11.4z"></path>
|
|
</svg>
|
|
<div>Profil in der Datenbank vorhanden. Bewerbung kann erfolgen.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</section>
|
|
|
|
{{--<section>
|
|
@if($currentPubkey && !$currentPleb->application_for && $currentPleb->association_status->value < 2)
|
|
<h3 class="text-xl leading-snug text-[#1B1B1B] dark:text-gray-100 font-bold mb-1">
|
|
passives Mitglied werden
|
|
</h3>
|
|
<h4 class="text-xs leading-snug text-[#1B1B1B] dark:text-gray-100 font-italic mb-1">
|
|
Passivmitglieder haben kein Stimmrecht. Firmen können nur Passivmitglieder werden und zahlen das 100-fache des festgelegten Beitrags.
|
|
</h4>
|
|
<div class="text-sm">
|
|
<x-textarea
|
|
corner="Beschreibe deine Motivation, passives Mitglied zu werden."
|
|
label="Warum möchtest du passives Mitglied werden?"
|
|
wire:model="form.reason"/>
|
|
</div>
|
|
<div class="sm:flex sm:items-center space-y-4 sm:space-y-0 sm:space-x-4 mt-5">
|
|
<div class="sm:w-1/3 flex flex-col space-y-2">
|
|
<x-button label="Für passive Mitgliedschaft bewerben"
|
|
wire:click="save({{ \App\Enums\AssociationStatus::PASSIVE() }})"/>
|
|
<x-badge outline
|
|
label="Es wird im Anschluss ein Nostr Event erzeugt, das du mit dem Mitgliedsbeitrag zappen kannst, nachdem du bestätigt wurdest."/>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</section>--}}
|
|
|
|
<section>
|
|
@if($currentPubkey && !$currentPleb->application_for && $currentPleb->association_status->value < 2)
|
|
<h3 class="text-xl leading-snug text-[#1B1B1B] dark:text-gray-100 font-bold mb-1">
|
|
aktives Mitglied werden
|
|
</h3>
|
|
<h4 class="text-xs leading-snug text-[#1B1B1B] dark:text-gray-100 font-italic mb-1">
|
|
Aktivmitglieder arbeiten ehrenamtlich für den Verein, z.B. als Podcast-Moderator
|
|
oder Software-Entwickler. Der Vorstand wählt sie aus. Nur Menschen können
|
|
Aktivmitglieder werden, zahlen 21 Satoshis im Jahr und haben volles Stimmrecht.
|
|
</h4>
|
|
<div class="text-sm">
|
|
<x-textarea
|
|
corner="Woher kennen wir dich? Was möchtest du einbringen?"
|
|
description="Wir bitten dich mindestens von 3 aktiven Mitgliedern auf Nostr gefolgt zu werden."
|
|
label="Warum möchtest du aktives Mitglied werden?"
|
|
wire:model="form.reason"/>
|
|
</div>
|
|
<div class="sm:flex sm:items-center space-y-4 sm:space-y-0 sm:space-x-4 mt-5">
|
|
<div class="sm:w-1/3 flex flex-col space-y-2">
|
|
<x-button label="Für aktive Mitgliedschaft bewerben"
|
|
wire:click="save({{ \App\Enums\AssociationStatus::ACTIVE() }})"/>
|
|
<x-badge outline
|
|
label="Es wird im Anschluss ein Nostr Event erzeugt, das du mit dem Mitgliedsbeitrag zappen kannst, nachdem du bestätigt wurdest."/>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</section>
|
|
|
|
<section>
|
|
@if($currentPubkey && $currentPleb->application_for)
|
|
<div
|
|
class="inline-flex flex-col w-full max-w-lg px-4 py-2 rounded-lg text-sm bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700/60 text-gray-600 dark:text-gray-400">
|
|
<div class="flex w-full justify-between items-start">
|
|
<div class="flex">
|
|
<svg class="shrink-0 fill-current text-yellow-500 mt-[3px] mr-3" width="16"
|
|
height="16" viewBox="0 0 16 16">
|
|
<path
|
|
d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm0 12c-.6 0-1-.4-1-1s.4-1 1-1 1 .4 1 1-.4 1-1 1zm1-3H7V4h2v5z"></path>
|
|
</svg>
|
|
<div>
|
|
<div class="font-medium text-gray-800 dark:text-gray-100 mb-1">
|
|
Du hast dich erfolgreich mit folgendem Grund beworben:
|
|
</div>
|
|
<div>{{ $currentPleb->application_text }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</section>
|
|
|
|
<section>
|
|
@if($currentPleb && $currentPleb->association_status->value > 1)
|
|
<div
|
|
class="inline-flex flex-col w-full max-w-lg px-4 py-2 rounded-lg text-sm bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700/60 text-gray-600 dark:text-gray-400">
|
|
<div class="flex w-full justify-between items-start">
|
|
<div class="flex">
|
|
<svg class="shrink-0 fill-current text-yellow-500 mt-[3px] mr-3" width="16"
|
|
height="16" viewBox="0 0 16 16">
|
|
<path
|
|
d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm0 12c-.6 0-1-.4-1-1s.4-1 1-1 1 .4 1 1-.4 1-1 1zm1-3H7V4h2v5z"></path>
|
|
</svg>
|
|
<div>
|
|
<div class="font-medium text-gray-800 dark:text-gray-100 mb-1">
|
|
Dein aktueller
|
|
Status: {{ $currentPleb->association_status->label() }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</section>
|
|
|
|
<section>
|
|
@if($currentPleb && $currentPleb->association_status->value > 1)
|
|
<div
|
|
class="inline-flex flex-col w-full px-4 py-2 rounded-lg text-sm bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700/60 text-gray-600 dark:text-gray-400">
|
|
<div class="flex w-full justify-between items-start">
|
|
<div class="flex">
|
|
<svg class="shrink-0 fill-current text-yellow-500 mt-[3px] mr-3" width="16"
|
|
height="16" viewBox="0 0 16 16">
|
|
<path
|
|
d="M8 0C3.6 0 0 3.6 0 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm0 12c-.6 0-1-.4-1-1s.4-1 1-1 1 .4 1 1-.4 1-1 1zm1-3H7V4h2v5z"></path>
|
|
</svg>
|
|
<div>
|
|
<div
|
|
class="font-medium text-gray-800 dark:text-gray-100 mb-1 space-y-2">
|
|
<p>Nostr Event für die Zahlung des
|
|
Mitgliedsbeitrags: <span
|
|
class="break-all">{{ $currentPleb->paymentEvents->first()->event_id }}</span>
|
|
</p>
|
|
<div>
|
|
@if(isset($events[0]))
|
|
<p>{{ $events[0]['content'] }}</p>
|
|
<div class="mt-8">
|
|
@if(!$invoice && !$currentYearIsPaid)
|
|
<div class="flex justify-center">
|
|
<button
|
|
@click="zap('{{ date('Y') }}', '{{ $currentPubkey }}', {{ $amountToPay }}, '{{ config('app.env') }}')"
|
|
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"
|
|
>
|
|
<i class="fa-sharp-duotone fa-solid fa-bolt-lightning mr-2"></i>
|
|
Zap
|
|
</button>
|
|
</div>
|
|
@else
|
|
@if(!$currentYearIsPaid && $qrCode)
|
|
<div class="flex justify-center"
|
|
wire:key="qrcode"
|
|
wire:poll="listenForPayment">
|
|
<a href="lightning:{{ $invoice }}">
|
|
<img
|
|
class="p-4 sm:p-12 bg-white"
|
|
src="{{ 'data:image/png;base64, '. $qrCode }}"
|
|
alt="qrcode">
|
|
</a>
|
|
</div>
|
|
@else
|
|
@if($currentYearIsPaid)
|
|
<div class="flex sm:justify-center">
|
|
<button
|
|
class="btn sm: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"
|
|
>
|
|
<i class="fa-sharp-duotone fa-solid fa-check-circle mr-2"></i>
|
|
aktuelles Jahr bezahlt
|
|
</button>
|
|
</div>
|
|
@endif
|
|
@endif
|
|
@endif
|
|
</div>
|
|
@endif
|
|
</div>
|
|
<section>
|
|
<h3 class="text-xl leading-snug text-gray-800 dark:text-gray-100 font-bold mb-1">
|
|
bisherige Zahlungen</h3>
|
|
<!-- Table -->
|
|
<table class="table-auto w-full dark:text-gray-400">
|
|
<!-- Table header -->
|
|
<thead
|
|
class="text-xs uppercase text-gray-400 dark:text-gray-500">
|
|
<tr class="flex flex-wrap md:table-row md:flex-no-wrap">
|
|
<th class="w-full hidden md:w-auto md:table-cell py-2">
|
|
<div class="font-semibold text-left">Satoshis</div>
|
|
</th>
|
|
<th class="w-full hidden md:w-auto md:table-cell py-2">
|
|
<div class="font-semibold text-left">Jahr</div>
|
|
</th>
|
|
<th class="w-full hidden md:w-auto md:table-cell py-2">
|
|
<div class="font-semibold text-left">Event-ID</div>
|
|
</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>
|
|
{{ collect(json_decode(collect($payment['tags'])->firstWhere('0', 'description')[1], true, 512, JSON_THROW_ON_ERROR)['tags'])->firstWhere('0', 'amount')[1] / 1000 }}
|
|
</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['content'] }}
|
|
</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['id'] }}</div>
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</section>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
@endvolt
|
|
</x-layouts.app>
|