diff --git a/resources/views/livewire/association/profile.blade.php b/resources/views/livewire/association/profile.blade.php
index 765cec6..cbe13d5 100644
--- a/resources/views/livewire/association/profile.blade.php
+++ b/resources/views/livewire/association/profile.blade.php
@@ -29,6 +29,12 @@ new class extends Component {
public ?string $nip05Handle = '';
+ public bool $nip05Verified = false;
+
+ public ?string $nip05VerifiedHandle = null;
+
+ public bool $nip05HandleMismatch = false;
+
public array $yearsPaid = [];
public array $events = [];
@@ -63,8 +69,30 @@ new class extends Component {
if ($this->currentPleb) {
$this->email = $this->currentPleb->email;
if ($this->currentPleb->nip05_handle) {
- $this->nip05Handle = strtolower(str_replace('@einundzwanzig.space', '',
- $this->currentPleb->nip05_handle));
+ $this->nip05Handle = $this->currentPleb->nip05_handle;
+
+ // Verify NIP-05 handle against nostr.json
+ try {
+ $response = \Illuminate\Support\Facades\Http::get(
+ 'https://einundzwanzig.space/.well-known/nostr.json',
+ );
+ $data = $response->json();
+ if (isset($data['names'])) {
+ foreach ($data['names'] as $handle => $pubkey) {
+ if ($pubkey === $this->currentPubkey) {
+ $this->nip05Verified = true;
+ $this->nip05VerifiedHandle = $handle;
+ // Check if verified handle differs from database handle
+ if ($handle !== $this->nip05Handle) {
+ $this->nip05HandleMismatch = true;
+ }
+ break;
+ }
+ }
+ }
+ } catch (\Exception) {
+ // Silently fail if nostr.json is not accessible
+ }
}
$this->no = $this->currentPleb->no_email;
$this->showEmail = !$this->no;
@@ -114,7 +142,7 @@ new class extends Component {
'nip05Handle' => 'required|string|max:255|regex:/^[a-z0-9_-]+$/|unique:einundzwanzig_plebs,nip05_handle',
]);
- $nip05Handle = strtolower($this->nip05Handle).'@einundzwanzig.space';
+ $nip05Handle = strtolower($this->nip05Handle);
$this->currentPleb->update([
'nip05_handle' => $nip05Handle,
@@ -399,6 +427,39 @@ new class extends Component {
vertrauenswürdiger.
+
+
+ @if($nip05Verified)
+ @if($nip05HandleMismatch)
+
+
+ Dein aktiviertes Handle ist {{ $nip05VerifiedHandle }}@einundzwanzig.space
+
+
+ Die Synchronisation zu {{ $nip05Handle }}@einundzwanzig.space wird automatisch im Hintergrund durchgeführt.
+
+
+ @else
+
+
+ Dein Handle {{ $nip05VerifiedHandle }}@einundzwanzig.space ist aktiv verifiziert!
+
+
+ Dein Handle ist in der NIP-05 Konfiguration eingetragen und bereit für die Verwendung.
+
+
+ @endif
+ @elseif($nip05Handle)
+
+
+ Dein Handle {{ $nip05Handle }}@einundzwanzig.space ist noch nicht aktiv.
+
+
+ Das Handle ist gespeichert, aber noch nicht in der NIP-05 Konfiguration veröffentlicht.
+ Der Vorstand wird dies bald aktivieren.
+
+
+ @endif
@else
diff --git a/resources/views/livewire/association/project-support/form/create.blade.php b/resources/views/livewire/association/project-support/form/create.blade.php
index 4d350e1..6f6290c 100644
--- a/resources/views/livewire/association/project-support/form/create.blade.php
+++ b/resources/views/livewire/association/project-support/form/create.blade.php
@@ -5,12 +5,15 @@ use App\Support\NostrAuth;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
+use Livewire\WithFileUploads;
new
#[Layout('layouts.app')]
#[Title('Projektförderung anlegen')]
class extends Component
{
+ use WithFileUploads;
+
public array $form = [
'name' => '',
'description' => '',
@@ -20,6 +23,8 @@ class extends Component
'sats_paid' => 0,
];
+ public $file = null;
+
public bool $isAllowed = false;
public bool $isAdmin = false;
@@ -40,6 +45,14 @@ class extends Component
}
}
+ public function removeFile(): void
+ {
+ if ($this->file) {
+ $this->file->delete();
+ $this->file = null;
+ }
+ }
+
public function save(): void
{
$this->validate([
@@ -47,9 +60,10 @@ class extends Component
'form.description' => 'required|string',
'form.support_in_sats' => 'required|integer|min:0',
'form.website' => 'required|url|max:255',
+ 'file' => 'nullable|file|mimes:jpeg,png,jpg,gif,webp|max:10240',
]);
- ProjectProposal::query()->create([
+ $projectProposal = ProjectProposal::query()->create([
'name' => $this->form['name'],
'description' => $this->form['description'],
'support_in_sats' => (int) $this->form['support_in_sats'],
@@ -59,6 +73,10 @@ class extends Component
'einundzwanzig_pleb_id' => \App\Models\EinundzwanzigPleb::query()->where('pubkey', NostrAuth::pubkey())->first()->id,
]);
+ if ($this->file) {
+ $projectProposal->addMedia($this->file)->toMediaCollection('main');
+ }
+
$this->redirectRoute('association.projectSupport');
}
};
@@ -70,8 +88,11 @@ class extends Component
class="flex flex-col md:flex-row items-center mb-6 space-y-4 md:space-y-0 md:space-x-4">
- Projektförderung anlegen
+ Projektförderungs-Antrag anlegen
+
+ Zurück
+
@@ -97,6 +118,30 @@ class extends Component
+
+ Bild
+
+
+
+
+
+ @if($file)
+
+
+
+
+
+
+
+ @endif
+
diff --git a/resources/views/livewire/association/project-support/form/edit.blade.php b/resources/views/livewire/association/project-support/form/edit.blade.php
index 4818a0c..bed98d1 100644
--- a/resources/views/livewire/association/project-support/form/edit.blade.php
+++ b/resources/views/livewire/association/project-support/form/edit.blade.php
@@ -5,12 +5,15 @@ use App\Support\NostrAuth;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
+use Livewire\WithFileUploads;
new
#[Layout('layouts.app')]
#[Title('Projektförderung bearbeiten')]
class extends Component
{
+ use WithFileUploads;
+
public ProjectProposal $project;
public array $form = [
@@ -22,6 +25,8 @@ class extends Component
'sats_paid' => 0,
];
+ public $file = null;
+
public bool $isAllowed = false;
public bool $isAdmin = false;
@@ -58,6 +63,21 @@ class extends Component
}
}
+ public function deleteMainImage(): void
+ {
+ if ($this->project->getFirstMedia('main')) {
+ $this->project->getFirstMedia('main')->delete();
+ }
+ }
+
+ public function removeFile(): void
+ {
+ if ($this->file) {
+ $this->file->delete();
+ $this->file = null;
+ }
+ }
+
public function update(): void
{
$this->validate([
@@ -65,6 +85,7 @@ class extends Component
'form.description' => 'required|string',
'form.support_in_sats' => 'required|integer|min:0',
'form.website' => 'required|url|max:255',
+ 'file' => 'nullable|file|mimes:jpeg,png,jpg,gif,webp|max:10240',
]);
$this->project->update([
@@ -76,6 +97,10 @@ class extends Component
'sats_paid' => $this->isAdmin ? $this->form['sats_paid'] : $this->project->sats_paid,
]);
+ if ($this->file) {
+ $this->project->addMedia($this->file)->toMediaCollection('main');
+ }
+
$this->redirectRoute('association.projectSupport.item', $this->project);
}
};
@@ -88,8 +113,11 @@ class extends Component
class="flex flex-col md:flex-row items-center mb-6 space-y-4 md:space-y-0 md:space-x-4">
- Projektförderung bearbeiten
+ Projektförderungs-Antrag bearbeiten
+
+ Zurück
+
@@ -121,6 +149,46 @@ class extends Component
+
+
+ Bild
+
+
+
+
+
+ @if($file)
+
+
+
+
+
+
+
+ @endif
+
+
+ @if($project->getFirstMedia('main'))
+
+
+
+
+
+
+
+ @endif
+
diff --git a/resources/views/livewire/association/project-support/index.blade.php b/resources/views/livewire/association/project-support/index.blade.php
index 3bbea4d..bf1c674 100644
--- a/resources/views/livewire/association/project-support/index.blade.php
+++ b/resources/views/livewire/association/project-support/index.blade.php
@@ -1,5 +1,6 @@
loadProjects();
- if (NostrAuth::check()) {
- $this->currentPubkey = NostrAuth::pubkey();
- $this->currentPleb = EinundzwanzigPleb::query()->where('pubkey', $this->currentPubkey)->first();
- $this->isAllowed = true;
- }
}
public function updatedSearch(): void
@@ -134,44 +130,46 @@ new class extends Component {
-
+
Unterstützt
-
+
Abgelehnt
- {{ $projects->count() }} Projekte
+ {{ $projects->count() }} Projekte
-
-
- @foreach($this->projects as $project)
-
- @endforeach
-
+
+
+ @foreach($this->projects as $project)
+
+ @endforeach
+
-
-
-
-
-
Projektunterstützung löschen?
-
- Du bist dabei, diese Projektunterstützung zu löschen.
- Diese Aktion kann nicht rückgängig gemacht werden.
-
-
-
-
-
- Abbrechen
-
- Löschen
-
-
-
-
+
+
+
+
+
Projektunterstützung löschen?
+
+ Du bist dabei, diese Projektunterstützung zu löschen.
+ Diese Aktion kann nicht rückgängig gemacht werden.
+
+
+
+
+
+ Abbrechen
+
+ Löschen
+
+
+
+
diff --git a/resources/views/livewire/association/project-support/show.blade.php b/resources/views/livewire/association/project-support/show.blade.php
index 2064539..f8816a1 100644
--- a/resources/views/livewire/association/project-support/show.blade.php
+++ b/resources/views/livewire/association/project-support/show.blade.php
@@ -1,6 +1,7 @@
projectProposal = \App\Models\ProjectProposal::query()->where('slug', $projectProposal)->firstOrFail();
+ $this->projectProposal = ProjectProposal::query()->where('slug', $projectProposal)->firstOrFail();
if (NostrAuth::check()) {
$this->currentPubkey = NostrAuth::pubkey();
$this->isAllowed = true;
+ $this->mountWithNostrAuth();
+ $this->ownVoteExists = Vote::query()
+ ->where('project_proposal_id', $this->projectProposal->id)
+ ->where('einundzwanzig_pleb_id', $this->currentPleb->id)
+ ->exists();
}
}
@@ -54,6 +60,10 @@ new class extends Component {
], [
'value' => true,
]);
+ $this->ownVoteExists = Vote::query()
+ ->where('project_proposal_id', $this->projectProposal->id)
+ ->where('einundzwanzig_pleb_id', $this->currentPleb->id)
+ ->exists();
}
public function handleNotApprove(): void
@@ -64,6 +74,10 @@ new class extends Component {
], [
'value' => false,
]);
+ $this->ownVoteExists = Vote::query()
+ ->where('project_proposal_id', $this->projectProposal->id)
+ ->where('einundzwanzig_pleb_id', $this->currentPleb->id)
+ ->exists();
}
}
?>
diff --git a/tests/Feature/Livewire/Association/ProjectSupportTest.php b/tests/Feature/Livewire/Association/ProjectSupportTest.php
index 9593dd6..99043bb 100644
--- a/tests/Feature/Livewire/Association/ProjectSupportTest.php
+++ b/tests/Feature/Livewire/Association/ProjectSupportTest.php
@@ -226,3 +226,81 @@ it('displays project details', function () {
->assertSee('Test Project Name')
->assertSee('Test Project Description');
});
+
+it('initializes currentPleb when authenticated', function () {
+ $pleb = EinundzwanzigPleb::factory()->create();
+ $project = ProjectProposal::factory()->create();
+
+ NostrAuth::login($pleb->pubkey);
+
+ Livewire::test('association.project-support.show', ['project' => $project])
+ ->assertSet('currentPleb.id', $pleb->id);
+});
+
+it('initializes ownVoteExists to false when no vote exists', function () {
+ $pleb = EinundzwanzigPleb::factory()->create();
+ $project = ProjectProposal::factory()->create();
+
+ NostrAuth::login($pleb->pubkey);
+
+ Livewire::test('association.project-support.show', ['project' => $project])
+ ->assertSet('ownVoteExists', false)
+ ->assertSee('Zustimmen')
+ ->assertSee('Ablehnen');
+});
+
+it('initializes ownVoteExists to true when vote exists', function () {
+ $pleb = EinundzwanzigPleb::factory()->create();
+ $project = ProjectProposal::factory()->create();
+ \App\Models\Vote::create([
+ 'project_proposal_id' => $project->id,
+ 'einundzwanzig_pleb_id' => $pleb->id,
+ 'value' => true,
+ ]);
+
+ NostrAuth::login($pleb->pubkey);
+
+ Livewire::test('association.project-support.show', ['project' => $project])
+ ->assertSet('ownVoteExists', true)
+ ->assertDontSee('Zustimmen')
+ ->assertDontSee('Ablehnen')
+ ->assertSee('Du hast bereits abgestimmt.');
+});
+
+it('can handle approve vote', function () {
+ $pleb = EinundzwanzigPleb::factory()->create();
+ $project = ProjectProposal::factory()->create();
+
+ NostrAuth::login($pleb->pubkey);
+
+ Livewire::test('association.project-support.show', ['project' => $project])
+ ->call('handleApprove')
+ ->assertHasNoErrors();
+
+ $vote = \App\Models\Vote::query()
+ ->where('project_proposal_id', $project->id)
+ ->where('einundzwanzig_pleb_id', $pleb->id)
+ ->first();
+
+ expect($vote)->not->toBeNull()
+ ->and($vote->value)->toBeTrue();
+});
+
+it('can handle not approve vote', function () {
+ $pleb = EinundzwanzigPleb::factory()->create();
+ $project = ProjectProposal::factory()->create();
+
+ NostrAuth::login($pleb->pubkey);
+
+ Livewire::test('association.project-support.show', ['project' => $project])
+ ->call('handleNotApprove')
+ ->assertHasNoErrors();
+
+ $vote = \App\Models\Vote::query()
+ ->where('project_proposal_id', $project->id)
+ ->where('einundzwanzig_pleb_id', $pleb->id)
+ ->first();
+
+ expect($vote)->not->toBeNull()
+ ->and($vote->value)->toBeFalse();
+});