cleanup and start with nostr

This commit is contained in:
HolgerHatGarKeineNode
2023-11-20 18:10:33 +01:00
parent df1eb750b7
commit a392e6fee0
218 changed files with 31 additions and 17474 deletions

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Http\Controllers\Export;
use App\Exports\MeetupEventAttendeesExport;
use App\Http\Controllers\Controller;
use App\Models\MeetupEvent;
use Illuminate\Http\Request;
class MeetupEventAttendeesExportController extends Controller
{
/**
* Handle the incoming request.
*/
public function __invoke(Request $request, MeetupEvent $meetupEvent)
{
return (new MeetupEventAttendeesExport($meetupEvent))->download($meetupEvent->start->toDateString().'_'.$meetupEvent->meetup->slug.'.xlsx');
}
}

View File

@@ -1,28 +0,0 @@
<?php
namespace App\Http\Livewire\Auth;
use Livewire\Component;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
class Auth47Component extends Component
{
public ?string $k1 = null;
protected ?string $url = null;
public function mount()
{
$this->k1 = bin2hex(str()->random(32));
$this->url = 'auth47://'.$this->k1.'?c=https://einundzwanzig.eu-1.sharedwithexpose.com/auth/auth47-callback&r=https://einundzwanzig.eu-1.sharedwithexpose.com/auth/auth47-callback';
$this->qrCode = base64_encode(QrCode::format('png')
->size(600)
->errorCorrection('L')
->generate($this->url));
}
public function render()
{
return view('livewire.auth.auth47-component')->layout('layouts.guest');
}
}

View File

@@ -1,73 +0,0 @@
<?php
namespace App\Http\Livewire\Auth;
use App\Models\LoginKey;
use App\Models\User;
use App\Notifications\ModelCreatedNotification;
use eza\lnurl;
use Livewire\Component;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
class LNUrlAuth extends Component
{
public ?string $k1 = null;
protected ?string $url = null;
protected ?string $lnurl = null;
protected ?string $qrCode = null;
public function switchToEmailLogin()
{
return to_route('login');
}
public function switchToEmailSignup()
{
return to_route('register');
}
public function mount()
{
$this->k1 = bin2hex(str()->random(32));
if (app()->environment('local')) {
$this->url = 'https://einundzwanzig.eu-1.sharedwithexpose.com/api/lnurl-auth-callback?tag=login&k1='.$this->k1.'&action=login';
} else {
$this->url = url('/api/lnurl-auth-callback?tag=login&k1='.$this->k1.'&action=login');
}
$this->lnurl = lnurl\encodeUrl($this->url);
$this->qrCode = base64_encode(QrCode::format('png')
->size(300)
->merge('/public/android-chrome-192x192.png', .3)
->errorCorrection('H')
->generate($this->lnurl));
}
public function checkAuth()
{
$loginKey = LoginKey::query()
->where('k1', $this->k1)
->whereDate('created_at', '>=', now()->subMinutes(5))
->first();
// you should also restrict this 👆🏻 by time, and find only the $k1 that were created in the last 5 minutes
if ($loginKey) {
$user = User::find($loginKey->user_id);
\App\Models\User::find(1)
->notify(new ModelCreatedNotification($user, 'users'));
auth()->login($user);
return to_route('welcome');
}
return true;
}
public function render()
{
return view('livewire.auth.ln-url-auth')->layout('layouts.guest');
}
}

View File

@@ -1,72 +0,0 @@
<?php
namespace App\Http\Livewire\Auth;
use App\Models\Team;
use App\Models\User;
use Livewire\Component;
class Login extends Component
{
public array $userProfile = [];
public function rules()
{
return [
'userProfile.npub' => 'required|string',
'userProfile.pubkey' => 'required|string',
'userProfile.banner' => 'required|string',
'userProfile.image' => 'required|string',
'userProfile.name' => 'required|string',
'userProfile.username' => 'required|string',
'userProfile.website' => 'required|string',
'userProfile.about' => 'required|string',
'userProfile.displayName' => 'required|string',
'userProfile.lud16' => 'required|string',
'userProfile.nip05' => 'required|string',
];
}
public function login($value)
{
if ($value) {
$firstUser = User::query()->where('nostr', $value)->first();
if ($firstUser) {
auth()->login($firstUser, true);
return to_route('welcome');
} else {
$fakeName = str()->random(10);
// create User
$user = User::create([
'is_lecturer' => true,
'name' => $fakeName,
'email' => str($fakeName)->slug() . '@portal.einundzwanzig.space',
'email_verified_at' => now(),
'lnbits' => [
'read_key' => null,
'url' => null,
'wallet_id' => null,
],
'nostr' => $value,
]);
$user->ownedTeams()
->save(Team::forceCreate([
'user_id' => $user->id,
'name' => $fakeName . "'s Team",
'personal_team' => true,
]));
auth()->login($user, true);
return to_route('welcome');
}
}
}
public function render()
{
return view('livewire.auth.login')->layout('layouts.guest');
}
}

View File

@@ -1,44 +0,0 @@
<?php
namespace App\Http\Livewire\Auth;
use App\Models\User;
use Livewire\Component;
class LoginWithNDK extends Component
{
public $existingAccount = false;
public array $userProfile = [];
public function rules()
{
return [
'userProfile.npub' => 'required|string',
'userProfile.pubkey' => 'required|string',
'userProfile.banner' => 'required|string',
'userProfile.image' => 'required|string',
'userProfile.name' => 'required|string',
'userProfile.username' => 'required|string',
'userProfile.website' => 'required|string',
'userProfile.about' => 'required|string',
'userProfile.displayName' => 'required|string',
'userProfile.lud16' => 'required|string',
'userProfile.nip05' => 'required|string',
];
}
public function updatedUserProfile($value)
{
if (User::query()->where('nostr', $value['npub'])->exists()) {
$this->existingAccount = true;
}
}
public function render()
{
return view('livewire.auth.login-with-n-d-k')->layout('layouts.guest');
}
}

View File

@@ -1,30 +0,0 @@
<?php
namespace App\Http\Livewire\Banner;
use App\Console\Commands\MempoolSpace\CacheRecommendedFees;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Http;
use Livewire\Component;
class MempoolWeather extends Component
{
public $weather;
public $changed;
public function mount()
{
/*if (cache()->has('mempool-weather')) {
$this->weather = cache()->get('mempool-weather');
} else {
Artisan::call(CacheRecommendedFees::class);
$this->weather = cache()->get('mempool-weather');
}
$this->changed = cache()->get('mempool-weather-changed');*/
}
public function render()
{
return view('livewire.banner.mempool-weather');
}
}

View File

@@ -1,95 +0,0 @@
<?php
namespace App\Http\Livewire\BitcoinEvent;
use App\Models\BitcoinEvent;
use App\Models\Country;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class BitcoinEventTable extends Component
{
public Country $country;
public ?int $year = null;
protected $queryString = ['year'];
public function mount()
{
if (! $this->year) {
$this->year = now()->year;
}
}
public function render()
{
return view('livewire.bitcoin-event.bitcoin-event-table', [
'markers' => BitcoinEvent::query()
->with([
'venue.city.country',
])
->where('bitcoin_events.from', '>=', now())
->where(fn ($query) => $query
->whereHas('venue.city.country',
fn ($query) => $query->where('countries.code', $this->country->code))
->orWhere('show_worldwide', true)
)
->get()
->map(fn ($event) => [
'id' => $event->id,
'name' => $event->title,
'coords' => [$event->venue->city->latitude, $event->venue->city->longitude],
]),
'events' => BitcoinEvent::query()
->where('bitcoin_events.from', '>=', now())
->where(fn ($query) => $query
->whereHas('venue.city.country',
fn ($query) => $query->where('countries.code', $this->country->code))
->orWhere('show_worldwide', true)
)
->get()
->map(fn ($event) => [
'id' => $event->id,
'startDate' => $event->from,
'endDate' => $event->to,
'location' => $event->title,
'description' => $event->description,
]),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Bitcoin Events'),
description: __('Search out a Bitcoin Event'),
image: asset('img/screenshot.png')
),
]);
}
public function filterByMarker($id)
{
return to_route('bitcoinEvent.table.bitcoinEvent', [
'#table',
'country' => $this->country->code,
'year' => $this->year,
'bitcoin_events' => [
'filters' => [
'byid' => $id,
],
],
]);
}
public function popover($content, $ids)
{
return to_route('bitcoinEvent.table.bitcoinEvent', [
'#table',
'country' => $this->country->code,
'year' => $this->year,
'bitcoin_events' => [
'filters' => [
'byid' => $ids,
],
],
]);
}
}

View File

@@ -1,90 +0,0 @@
<?php
namespace App\Http\Livewire\BitcoinEvent\Form;
use App\Models\BitcoinEvent;
use Illuminate\Validation\Rule;
use Livewire\Component;
use Livewire\WithFileUploads;
use WireUi\Traits\Actions;
class BitcoinEventForm extends Component
{
use WithFileUploads;
use Actions;
public string $country;
public ?BitcoinEvent $bitcoinEvent = null;
public $image;
public ?string $fromUrl = '';
protected $queryString = [
'fromUrl' => [
'except' => null,
],
];
public function rules()
{
return [
'image' => [Rule::requiredIf(!$this->bitcoinEvent->id), 'nullable', 'mimes:jpeg,png,jpg,gif', 'max:10240'],
'bitcoinEvent.venue_id' => 'required',
'bitcoinEvent.from' => 'required',
'bitcoinEvent.to' => 'required',
'bitcoinEvent.title' => 'required',
'bitcoinEvent.description' => 'required',
'bitcoinEvent.link' => 'required|url',
'bitcoinEvent.show_worldwide' => 'bool',
];
}
public function mount()
{
if (!$this->bitcoinEvent) {
$this->bitcoinEvent = new BitcoinEvent(
[
'description' => '',
'show_worldwide' => true,
]
);
} elseif (!auth()
->user()
->can('update', $this->bitcoinEvent)) {
abort(403);
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
}
public function deleteMe()
{
$this->bitcoinEvent->delete();
return redirect($this->fromUrl);
}
public function submit()
{
$this->validate();
$this->bitcoinEvent->save();
if ($this->image) {
$this->bitcoinEvent->addMedia($this->image)
->usingFileName(md5($this->image->getClientOriginalName()).'.'.$this->image->getClientOriginalExtension())
->toMediaCollection('logo');
}
return redirect($this->fromUrl);
}
public function render()
{
return view('livewire.bitcoin-event.form.bitcoin-event-form');
}
}

View File

@@ -1,48 +0,0 @@
<?php
namespace App\Http\Livewire\BookCase;
use App\Models\BookCase;
use App\Models\Country;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class BookCaseTable extends Component
{
public ?Country $country = null;
public string $c = 'de';
public array $bookcases = [];
protected $queryString = ['bookcases'];
public function render()
{
return view('livewire.book-case.book-case-table', [
'markers' => ! isset($this->table['filters']['byids']) ? []
: BookCase::query()
->whereIn('id', str($this->table['filters']['byids'] ?? '')->explode(','))
->get()
->map(fn ($b) => [
'title' => $b->title,
'lat' => $b->latitude,
'lng' => $b->longitude,
'url' => route('bookCases.comment.bookcase', ['country' => $this->country, 'bookCase' => $b]),
'icon' => asset('img/btc-logo-6219386_1280.png'),
'icon_size' => [42, 42],
])
->toArray(),
'bookCases' => BookCase::query()->active()->get(),
'countries' => Country::query()
->select(['code', 'name'])
->get(),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Bookcases'),
description: __('Search out a public bookcase'),
image: asset('img/screenshot.png')
),
]);
}
}

View File

@@ -1,31 +0,0 @@
<?php
namespace App\Http\Livewire\BookCase;
use App\Models\Country;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class CityTable extends Component
{
public Country $country;
public bool $manage = false;
protected $queryString = [
'manage' => [
'except' => false,
],
];
public function render()
{
return view('livewire.book-case.city-table')->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Bookcases'),
description: __('Search out a public bookcase'),
image: asset('img/screenshot.png')
),
]);
}
}

View File

@@ -1,67 +0,0 @@
<?php
namespace App\Http\Livewire\BookCase;
use App\Models\BookCase;
use App\Models\Country;
use Livewire\Component;
use Livewire\WithFileUploads;
use RalphJSmit\Laravel\SEO\Support\SEOData;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
class CommentBookCase extends Component
{
use WithFileUploads;
public Country $country;
public $photo;
public string $c = 'de';
public BookCase $bookCase;
public function save()
{
$this->validate([
'photo' => 'image|max:4096', // 4MB Max
]);
$this->bookCase
->addMedia($this->photo)
->usingFileName(md5($this->photo->getClientOriginalName()).'.'.$this->photo->getClientOriginalExtension())
->toMediaCollection('images');
return to_route('bookCases.comment.bookcase', ['country' => $this->country, 'bookCase' => $this->bookCase->id]);
}
public function deletePhoto($id)
{
Media::find($id)
->delete();
return to_route('bookCases.comment.bookcase', ['country' => $this->country, 'bookCase' => $this->bookCase->id]);
}
public function render()
{
return view('livewire.book-case.comment-book-case')
->layout('layouts.app', [
'SEOData' => new SEOData(
title: $this->bookCase->title,
description: $this->bookCase->address,
image: $this->bookCase->getFirstMediaUrl('images', 'seo') ?? asset('img/bookcase.jpg'),
),
]);
}
protected function url_to_absolute($url)
{
if (str($url)->contains('http')) {
return $url;
}
if (!str($url)->contains('http')) {
return str($url)->prepend('https://');
}
}
}

View File

@@ -1,91 +0,0 @@
<?php
namespace App\Http\Livewire\BookCase\Form;
use App\Gamify\Points\BookCaseOrangePilled;
use App\Models\BookCase;
use App\Models\Country;
use App\Models\OrangePill;
use Illuminate\Validation\Rule;
use Livewire\Component;
use Livewire\WithFileUploads;
class OrangePillForm extends Component
{
use WithFileUploads;
public Country $country;
public BookCase $bookCase;
public ?OrangePill $orangePill = null;
public $image;
public string $fromUrl = '';
protected $queryString = ['fromUrl' => ['except' => '']];
public function rules()
{
return [
'orangePill.book_case_id' => ['required'],
'orangePill.user_id' => ['required'],
'orangePill.amount' => ['required', 'numeric'],
'orangePill.date' => ['required', 'date'],
'orangePill.comment' => ['required', 'string'],
'image' => ['max:8192', Rule::requiredIf(!$this->orangePill->id), 'image', 'nullable'], // 8MB Max
];
}
public function mount()
{
if (!$this->orangePill) {
$this->orangePill = new OrangePill([
'user_id' => auth()->id(),
'book_case_id' => $this->bookCase->id,
'date' => now(),
'amount' => 1,
]);
} elseif ($this->orangePill->user_id !== auth()->id()) {
abort(403);
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
}
public function save()
{
if (!auth()->check()) {
return to_route('auth.login');
}
$this->validate();
$this->orangePill->save();
if ($this->image) {
$this->orangePill
->addMedia($this->image)
->usingFileName(md5($this->image->getClientOriginalName()).'.'.$this->image->getClientOriginalExtension())
->toMediaCollection('images');
}
return redirect($this->fromUrl);
}
public function deleteMe()
{
$this->orangePill->delete();
auth()
->user()
->undoPoint(new BookCaseOrangePilled($this->orangePill));
return redirect($this->fromUrl);
}
public function render()
{
return view('livewire.book-case.form.orange-pill-form');
}
}

View File

@@ -1,34 +0,0 @@
<?php
namespace App\Http\Livewire\BookCase;
use App\Models\BookCase;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class Heatmap extends Component
{
public string $country;
public function render()
{
$data = BookCase::query()
->active()
->whereHas('orangePills')
->get()
->map(fn ($bookCase) => [
'lat' => $bookCase->latitude,
'lng' => $bookCase->longitude,
]);
return view('livewire.book-case.heatmap', [
'heatmap_data' => $data->toArray(),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Heatmap of Bookcases'),
description: __('On this map you can see the success and spread of the Bitcoin books.'),
image: asset('img/heatmap_bookcases.png'),
),
]);
}
}

View File

@@ -1,63 +0,0 @@
<?php
namespace App\Http\Livewire\BookCase;
use App\Models\Country;
use App\Models\User;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class HighscoreTable extends Component
{
public Country $country;
public bool $viewingModal = false;
public ?User $modal = null;
public function render()
{
return view('livewire.book-case.highscore-table', [
'plebs' => User::query()
->with([
'reputations',
])
->withCount([
'orangePills',
])
->where('reputation', '>', 0)
->orderByDesc('reputation')
->get(),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Highscore Table'),
description: __('Hall of fame of our honorable plebs'),
image: asset('img/highscore_table_screenshot.png'),
),
]);
}
public function toggleChat()
{
$this->emit('toggleHighscoreChat');
}
public function openModal($id)
{
$this->modal = User::query()
->with([
'orangePills',
'reputations',
])
->where('id', $id)
->first();
$this->viewingModal = true;
}
public function resetModal()
{
$this->modal = null;
$this->viewingModal = false;
}
}

View File

@@ -1,18 +0,0 @@
<?php
namespace App\Http\Livewire\BookCase;
use App\Models\OrangePill;
use App\Models\User;
use Livewire\Component;
class Stats extends Component
{
public function render()
{
return view('livewire.book-case.stats', [
'orangePills' => OrangePill::query()->count(),
'plebs' => User::query()->whereHas('orangePills')->count(),
]);
}
}

View File

@@ -1,41 +0,0 @@
<?php
namespace App\Http\Livewire\BookCase;
use App\Models\BookCase;
use App\Models\Country;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class WorldMap extends Component
{
public Country $country;
public function render()
{
return view('livewire.book-case.world-map', [
'mapData' => BookCase::query()
->select(['id', 'latitude', 'longitude'])
->withCount('orangePills')
->active()
->get()
->map(fn ($bookCase) => [
'lat' => $bookCase->latitude,
'lng' => $bookCase->longitude,
'url' => url()->route('bookCases.comment.bookcase',
[
'country' => $this->country,
'bookCase' => $bookCase,
]),
'op' => $bookCase->orange_pills_count,
])
->toArray(),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('World Map of Bookcases'),
description: __('On this map you can see bookcases that have been orange pilled. You can also click on a marker to go to the search result.'),
image: asset('img/world_map_bookcases.png')
),
]);
}
}

View File

@@ -1,72 +0,0 @@
<?php
namespace App\Http\Livewire\Chat;
use App\Events\ChatMessageSentEvent;
use Livewire\Component;
class HighscoreChat extends Component
{
public bool $open = false;
public array $messages = [];
public string $myNewMessage = '';
public function rules()
{
return [
'myNewMessage' => 'required|min:1|max:255',
];
}
public function getListeners()
{
return [
'toggleHighscoreChat' => 'toggle',
'echo:plebchannel,.App\Events\ChatMessageSentEvent' => 'chatMessageSent',
];
}
public function mount()
{
$this->messages = cache()->get('highscore_chat_messages', []);
}
public function toggle()
{
$this->open = ! $this->open;
}
public function chatMessageSent()
{
if (auth()->check()) {
$this->messages = cache()->get('highscore_chat_messages', []);
$this->dispatchBrowserEvent('chat-updated');
}
}
public function sendMessage()
{
$this->validate();
$newMessages = collect(cache()->get('highscore_chat_messages', []))
->push([
'fromId' => auth()->id(),
'fromName' => str(auth()->user()->name)->limit(2),
'userImg' => str(auth()->user()->profile_photo_url)->replace('background=EBF4FF', 'background=F7931A'),
'message' => $this->myNewMessage,
'time' => now()->asDateTime(),
])
->take(-21)
->toArray();
cache()->set('highscore_chat_messages', $newMessages);
event(new ChatMessageSentEvent());
$this->messages = $newMessages;
$this->myNewMessage = '';
}
public function render()
{
return view('livewire.chat.highscore-chat');
}
}

View File

@@ -1,63 +0,0 @@
<?php
namespace App\Http\Livewire\City\Form;
use App\Models\City;
use Illuminate\Validation\Rule;
use Livewire\Component;
class CityForm extends Component
{
public ?City $city = null;
public string $fromUrl = '';
protected $queryString = [
'fromUrl' => [
'except' => null,
],
];
public function rules()
{
return [
'city.country_id' => 'required',
'city.name' => [
'required',
Rule::unique('cities', 'name')
->ignore($this->city),
],
'city.longitude' => 'required',
'city.latitude' => 'required',
];
}
public function mount()
{
if (!$this->city) {
$this->city = new City();
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
}
public function save()
{
$this->validate();
$this->city->longitude = str($this->city->longitude)
->replace(',', '.')
->toFloat();
$this->city->latitude = str($this->city->latitude)
->replace(',', '.')
->toFloat();
$this->city->save();
return redirect($this->fromUrl ?? url()->route('welcome'));
}
public function render()
{
return view('livewire.city.form.city-form');
}
}

View File

@@ -1,76 +0,0 @@
<?php
namespace App\Http\Livewire\ContentCreator\Form;
use App\Models\Lecturer;
use Illuminate\Validation\Rule;
use Livewire\Component;
use Livewire\WithFileUploads;
class ContentCreatorForm extends Component
{
use WithFileUploads;
public ?Lecturer $lecturer = null;
public $image;
public ?string $fromUrl = '';
protected $queryString = ['fromUrl' => ['except' => '']];
public function rules()
{
return [
'image' => [Rule::requiredIf(!$this->lecturer->id), 'nullable', 'mimes:jpeg,png,jpg,gif', 'max:10240'],
'lecturer.name' => [
'required',
Rule::unique('lecturers', 'name')
->ignore($this->lecturer),
],
'lecturer.active' => 'boolean',
'lecturer.subtitle' => 'nullable|string',
'lecturer.intro' => 'nullable|string',
'lecturer.paynym' => 'nullable|string',
'lecturer.nostr' => 'nullable|string',
'lecturer.twitter_username' => 'nullable|string',
'lecturer.website' => 'nullable|url',
'lecturer.lightning_address' => 'nullable|string',
'lecturer.lnurl' => 'nullable|string',
'lecturer.node_id' => 'nullable|string',
];
}
public function mount()
{
if (!$this->lecturer) {
$this->lecturer = new Lecturer([
'intro' => '',
'active' => true,
]);
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
}
public function save()
{
$this->validate();
$this->lecturer->save();
if ($this->image) {
$this->lecturer->addMedia($this->image)
->usingFileName(md5($this->image->getClientOriginalName()).'.'.$this->image->getClientOriginalExtension())
->toMediaCollection('avatar');
}
return redirect($this->fromUrl);
}
public function render()
{
return view('livewire.content-creator.form.content-creator-form');
}
}

View File

@@ -1,37 +0,0 @@
<?php
namespace App\Http\Livewire\Frontend;
use Illuminate\Support\Facades\Cookie;
use JoeDixon\Translation\Language;
use JoeDixon\Translation\Translation;
use Livewire\Component;
class Footer extends Component
{
public function render()
{
$l = Cookie::get('lang', config('app.locale'));
$language = Language::query()
->where('language', $l)
->first();
if (!$language || str($l)->contains('ey')) {
$language = Language::query()
->where('language', config('app.locale'))
->first();
}
$translated = $language->translations()
->whereNotNull('value')
->where('value', '<>', '')
->count();
$toTranslate = Translation::query()
->where('language_id', $language->id)
->count();
$toTranslate = $toTranslate > 0 ? $toTranslate : 1;
return view('livewire.frontend.footer', [
'percentTranslated' => $l === 'en' ? 100 : round(($translated / $toTranslate) * 100),
'language' => $language,
]);
}
}

View File

@@ -1,162 +0,0 @@
<?php
namespace App\Http\Livewire\Frontend;
use App\Models\BitcoinEvent;
use App\Models\City;
use App\Models\Country;
use App\Models\CourseEvent;
use App\Models\LibraryItem;
use App\Models\MeetupEvent;
use App\Models\OrangePill;
use App\Models\ProjectProposal;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\Route;
use Livewire\Component;
class Header extends Component
{
public ?Country $country = null;
public $currentRouteName;
public string $c = 'de';
public string $l = 'de';
public string $timezone;
public $bgColor = 'bg-21gray';
protected $queryString = ['l'];
protected $listeners = ['refresh' => '$refresh'];
public function rules()
{
return [
'c' => 'required',
'l' => 'required',
'timezone' => 'required',
];
}
public function mount()
{
$this->timezone = config('app.user-timezone');
$this->l = Cookie::get('lang') ?: config('app.locale');
$this->c = Cookie::get('country') ?: config('app.country');
if (!$this->country) {
$this->country = Country::query()
->where('code', $this->c)
->first();
}
$this->currentRouteName = Route::currentRouteName();
}
public function updatedTimezone($value)
{
auth()
->user()
->update(['timezone' => $value]);
return redirect(request()->header('Referer'));
}
public function updatedC($value)
{
Cookie::queue('country', $value, 60 * 24 * 365);
$url = str(request()->header('Referer'))->explode('/');
$url[3] = $value;
return redirect($url->implode('/'));
}
public function updatedL($value)
{
Cookie::queue('lang', $value, 60 * 24 * 365);
return redirect(request()->header('Referer'));
}
public function render()
{
return view('livewire.frontend.header', [
'news' => LibraryItem::query()
->with([
'createdBy.roles',
'lecturer',
'tags',
])
->where('type', 'markdown_article')
->where('approved', true)
->where('news', true)
->orderByDesc('created_at')
->take(2)
->get(),
'meetups' => MeetupEvent::query()
->with([
'meetup.users',
'meetup.city.country',
])
->where('start', '>', now())
->orderBy('start')
->take(2)
->get(),
'courseEvents' => CourseEvent::query()
->with([
'venue.city.country',
'course.lecturer',
])
->where('from', '>', now())
->orderBy('from')
->take(2)
->get(),
'libraryItems' => LibraryItem::query()
->with([
'lecturer',
])
->where('type', '<>', 'markdown_article')
->orderByDesc('created_at')
->take(2)
->get(),
'bitcoinEvents' => BitcoinEvent::query()
->with([
'venue',
])
->where('from', '>', now())
->orderBy('from')
->take(2)
->get(),
'orangePills' => OrangePill::query()
->with([
'user',
'bookCase',
])
->orderByDesc('date')
->take(2)
->get(),
'projectProposals' => ProjectProposal::query()
->with([
'votes',
'user',
])
->take(2)
->get(),
'cities' => City::query()
->select(['latitude', 'longitude'])
->get(),
'countries' => Country::query()
->select('id', 'name', 'code')
->orderBy('name')
->get()
->map(function (Country $country) {
$country->name = config('countries.emoji_flags')[str($country->code)
->upper()
->toString()].' '.$country->name;
return $country;
}),
]);
}
}

View File

@@ -1,15 +0,0 @@
<?php
namespace App\Http\Livewire\Frontend;
use Livewire\Component;
class SearchTabs extends Component
{
public string $country;
public function render()
{
return view('livewire.frontend.search-tabs');
}
}

View File

@@ -1,76 +0,0 @@
<?php
namespace App\Http\Livewire\Frontend;
use App\Models\Country;
use Illuminate\Support\Facades\Cookie;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class Welcome extends Component
{
public string $c = 'de';
public string $l = 'de';
protected $queryString = ['c', 'l'];
public function rules()
{
return [
'c' => 'required',
'l' => 'required',
];
}
public function mount()
{
$this->l = Cookie::get('lang') ?: config('app.locale');
$this->c = Cookie::get('country') ?: config('app.country');
Cookie::queue('lang', $this->l, 60 * 24 * 365);
Cookie::queue('country', $this->c, 60 * 24 * 365);
}
public function updated($property, $value)
{
$this->validate();
if ($property === 'c') {
$c = $value;
} else {
$c = $this->c;
}
if ($property === 'l') {
$l = $value;
} else {
$l = $this->l;
}
Cookie::queue('lang', $this->l, 60 * 24 * 365);
Cookie::queue('country', $this->c, 60 * 24 * 365);
return to_route('welcome', ['c' => $c, 'l' => $l]);
}
public function render()
{
return view('livewire.frontend.welcome', [
'countries' => Country::query()
->select('id', 'name', 'code')
->orderBy('name')
->get()
->map(function (Country $country) {
$country->name = config('countries.emoji_flags')[str($country->code)
->upper()
->toString()].' '.$country->name;
return $country;
}),
])->layout('layouts.guest', [
'SEOData' => new SEOData(
title: __('Welcome'),
description: __('Welcome to the portal of the Einundzwanzig Community.'),
image: url()->route('imgPublic', ['path' => 'img/screenshot.png', 'h' => 630, 'w' => 1200, 'fit' => 'crop'])
),
]);
}
}

View File

@@ -1,13 +0,0 @@
<?php
namespace App\Http\Livewire\Guest;
use Livewire\Component;
class Welcome extends Component
{
public function render()
{
return view('livewire.guest.welcome')->layout('layouts.guest');
}
}

View File

@@ -1,87 +0,0 @@
<?php
namespace App\Http\Livewire;
use App\Events\PaidMessageEvent;
use App\Traits\LNBitsTrait;
use Illuminate\Support\Facades\Log;
use Livewire\Component;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
use WireUi\Traits\Actions;
class Hello extends Component
{
use Actions;
use LNBitsTrait;
public $message = '';
public $qrCode = '';
public $invoice = '';
public $paymentHash = '';
public $checkid = null;
public bool $invoicePaid = false;
public function rules()
{
return [
'message' => 'required|string|max:1000',
];
}
public function mount()
{
try {
// {"url":"","wallet_id":"","read_key":""}
$invoice = $this->createInvoice(
sats: 21,
memo: 'Payment for: Bitcoin im Ländle 2023 - Code is Speech',
lnbits: [
'url' => config('services.lnbits.url'),
'wallet_id' => config('services.lnbits.wallet_id'),
'read_key' => config('services.lnbits.read_key'),
],
);
} catch (\Exception $e) {
$this->notification()
->error('LNBits error: '.$e->getMessage());
return;
}
$this->paymentHash = $invoice['payment_hash'];
$this->qrCode = base64_encode(QrCode::format('png')
->size(300)
->merge('/public/img/markus_turm.png', .3)
->errorCorrection('H')
->generate($invoice['payment_request']));
$this->invoice = $invoice['payment_request'];
$this->checkid = $invoice['checking_id'];
}
public function checkPaymentHash()
{
try {
$invoice = $this->check($this->checkid, [
'url' => config('services.lnbits.url'),
'wallet_id' => config('services.lnbits.wallet_id'),
'read_key' => config('services.lnbits.read_key'),
]);
} catch (\Exception $e) {
$this->notification()
->error('LNBits error: '.$e->getMessage());
return;
}
if (isset($invoice['paid']) && $invoice['paid']) {
$this->invoicePaid = true;
event(new PaidMessageEvent($this->message, $this->checkid));
} else {
Log::error(json_encode($invoice, JSON_THROW_ON_ERROR));
}
}
public function render()
{
return view('livewire.hello')->layout('layouts.guest');
}
}

View File

@@ -1,198 +0,0 @@
<?php
namespace App\Http\Livewire\Library\Form;
use App\Enums\LibraryItemType;
use App\Models\Country;
use App\Models\Library;
use App\Models\LibraryItem;
use App\Traits\HasTagsTrait;
use Illuminate\Validation\Rule;
use Livewire\Component;
use Livewire\WithFileUploads;
use Spatie\LaravelOptions\Options;
class LibraryItemForm extends Component
{
use HasTagsTrait;
use WithFileUploads;
public Country $country;
public ?LibraryItem $libraryItem = null;
public $library;
public $image;
public $file;
public bool $lecturer = false;
public bool $isBindle = false;
public ?string $fromUrl = '';
protected $queryString = [
'fromUrl' => ['except' => ''],
'lecturer' => ['except' => false],
'isBindle' => ['except' => false],
];
public function rules()
{
return [
'image' => [Rule::requiredIf(!$this->libraryItem->id), 'nullable', 'mimes:jpeg,png,jpg,gif', 'max:10240'],
'library' => 'required',
'selectedTags' => 'array|min:1',
'libraryItem.lecturer_id' => 'required',
'libraryItem.name' => 'required',
'libraryItem.type' => 'required',
'libraryItem.language_code' => 'required',
'libraryItem.value' => [
Rule::when($this->libraryItem->type !== LibraryItemType::DownloadableFile(), 'required'),
Rule::when(
$this->libraryItem->type !== LibraryItemType::MarkdownArticle()
&& $this->libraryItem->type !== LibraryItemType::MarkdownArticleExtern(), ['url']
),
],
'libraryItem.subtitle' =>
[
Rule::when(
$this->libraryItem->type !== 'bindle',
'required',
)
],
'libraryItem.excerpt' =>
[
Rule::when(
$this->libraryItem->type !== 'bindle',
'required',
)
],
'libraryItem.main_image_caption' =>
[
Rule::when(
$this->libraryItem->type !== 'bindle',
'required',
)
],
'libraryItem.read_time' =>
[
Rule::when(
$this->libraryItem->type !== 'bindle',
'required',
)
],
'libraryItem.approved' =>
[
Rule::when(
$this->libraryItem->type !== 'bindle',
'required',
)
],
];
}
public function mount()
{
if (!$this->libraryItem) {
$this->libraryItem = new LibraryItem([
'approved' => true,
'read_time' => 1,
'value' => ''
]);
if ($this->lecturer) {
$this->library = Library::query()
->firstWhere('name', '=', 'Dozentenmaterial')?->id;
}
} else {
$this->selectedTags = $this->libraryItem->tags()
->where('type', 'library_item')
->get()
->map(fn($tag) => $tag->name)
->toArray();
$this->library = $this->libraryItem->libraries()
->first()
->id;
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
if ($this->isBindle) {
$this->library = 21;
$this->libraryItem->lecturer_id = 125;
$this->libraryItem->type = 'bindle';
$this->libraryItem->language_code = 'de';
$this->selectedTags = ['Bindle'];
}
}
public function save()
{
$this->validate();
$this->libraryItem->save();
$this->libraryItem->setStatus('published');
$this->libraryItem->syncTagsWithType(
$this->selectedTags,
'library_item'
);
if ($this->image) {
$this->libraryItem->addMedia($this->image)
->usingFileName(md5($this->image->getClientOriginalName()) . '.' . $this->image->getClientOriginalExtension())
->toMediaCollection('main');
}
if ($this->file) {
$this->libraryItem->addMedia($this->file)
->usingFileName(md5($this->file->getClientOriginalName()) . '.' . $this->file->getClientOriginalExtension())
->toMediaCollection('single_file');
}
$this->libraryItem->libraries()
->syncWithoutDetaching([(int)$this->library]);
if ($this->libraryItem->type === 'bindle') {
return to_route('bindles');
}
return to_route('library.table.libraryItems', ['country' => $this->country]);
}
public function render()
{
$types = Options::forEnum(LibraryItemType::class)
->filter(
fn($type) => $type !== LibraryItemType::PodcastEpisode
&& $type !== LibraryItemType::MarkdownArticle
)
->toArray();
$libaries = Library::query()
->when(auth()->id() != config('portal.bonus.fiat-tracker-user-id'),
fn($query) => $query->where('name', '!=', 'Bindle')
)
->get()
->map(fn($library) => [
'id' => $library->id,
'name' => $library->name,
])
->toArray();
if (auth()->id() == config('portal.bonus.fiat-tracker-user-id')) {
$types = collect($types)->prepend([
'label' => 'Bindle',
'value' => 'bindle',
]);
}
return view('livewire.library.form.library-item-form', [
'types' => $types,
'libraries' => $libaries,
]);
}
}

View File

@@ -1,129 +0,0 @@
<?php
namespace App\Http\Livewire\Library;
use App\Models\Country;
use App\Models\Library;
use App\Models\LibraryItem;
use App\Models\Tag;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class LibraryTable extends Component
{
public Country $country;
public array $filters = [];
public bool $isLecturerPage = false;
public string $search = '';
public $perPage = 9;
public $currentTab = '*';
protected $queryString = [
'currentTab' => ['except' => '*'],
'filters' => ['except' => ''],
'search' => ['except' => ''],
];
public function loadMore()
{
$this->perPage += 9;
}
public function mount()
{
if (str(request()
->route()
->getName())->contains(['.lecturer'])) {
$this->isLecturerPage = true;
}
}
public function resetFiltering($isLecturerPage = false)
{
if ($isLecturerPage) {
return to_route('library.table.lecturer', ['country' => $this->country, 'currentTab' => '*']);
} else {
return to_route('library.table.libraryItems', ['country' => $this->country, 'currentTab' => '*']);
}
}
public function render()
{
$shouldBePublic = !$this->isLecturerPage;
$libraries = \App\Models\Library::query()
->where('name', '!=', 'Bindle')
->whereNull('parent_id')
->where('is_public', $shouldBePublic)
->orderBy('name')
->get();
$tabs = collect([
[
'name' => '*',
],
]);
foreach ($libraries as $library) {
$tabs->push([
'name' => $library->name,
]);
}
if ($this->currentTab !== '*') {
$parentLibrary = Library::query()
->where('name', $this->currentTab)
->first();
}
$searchTags = [];
if ($this->search) {
$searchTags = Tag::where('name', 'ilike', '%' . $this->search . '%')
->pluck('id')
->toArray();
}
return view('livewire.library.library-table', [
'libraries' => $tabs,
'libraryItems' => LibraryItem::query()
->with([
'lecturer',
'tags',
])
->where('type', '!=', 'bindle')
->when($this->search, fn($query) => $query
->where('name', 'ilike', '%' . $this->search . '%')
->orWhere(fn($query) => $query
->when(count($searchTags) > 0 && count($this->filters) < 1,
fn($query) => $query->whereHas('tags',
fn($query) => $query->whereIn('tags.id', $searchTags)))
)
)
->when($this->currentTab !== '*', fn($query) => $query
->whereHas('libraries',
fn($query) => $query
->where('libraries.name', $this->currentTab)
)
)
->when(isset($this->filters['lecturer_id']),
fn($query) => $query->where('library_items.lecturer_id',
$this->filters['lecturer_id'])
)
->when(isset($this->filters['tag']), fn($query) => $query->whereHas('tags',
fn($query) => $query->whereIn('tags.id', $this->filters['tag'])))
->when(isset($this->filters['language']),
fn($query) => $query->whereIn('language_code', $this->filters['language']))
->whereHas('libraries',
fn($query) => $query->where('libraries.is_public', $shouldBePublic))
->orderByDesc('library_items.created_at')
->paginate($this->perPage),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Library'),
description: __('Here you can find all content that are available in the library.'),
image: asset('img/screenshot.png')
),
]);
}
}

View File

@@ -1,60 +0,0 @@
<?php
namespace App\Http\Livewire\Library;
use App\Models\Country;
use App\Models\Episode;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class PodcastEpisodesTable extends Component
{
public Country $country;
public array $filters = [];
public string $search = '';
public $perPage = 9;
public $currentTab = '*';
protected $queryString = [
'filters' => ['except' => ''],
'search' => ['except' => ''],
];
public function loadMore()
{
$this->perPage += 9;
}
public function resetFiltering($isLecturerPage = false)
{
return to_route('library.table.podcastsEpisodes', ['country' => $this->country]);
}
public function render()
{
return view('livewire.library.podcast-episodes-table', [
'episodes' => Episode::query()
->with(['podcast'])
->whereNot('data->link', '=', '')
->when($this->search,
fn($query, $search) => $query
->where('data->title', 'ilike', "%{$search}%")
->orWhere('data->description', 'ilike', "%{$search}%")
->orWhereHas('podcast',
fn($query) => $query->where('data->title', 'ilike', "%{$search}%"))
)
->orderByDesc('data->datePublished')
->paginate($this->perPage),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Podcast Episodes'),
description: __('Search and find Bitcoin Podcast episodes.'),
image: asset('img/Screenshot_Podcast_Episodes.png')
),
]);
}
}

View File

@@ -1,51 +0,0 @@
<?php
namespace App\Http\Livewire\Library;
use App\Models\LibraryItem;
use App\Models\Tag;
use Livewire\Component;
class SearchByTagComponent extends Component
{
public string $country = 'de';
public array $filters = [];
protected $queryString = [
'filters' => ['except' => ''],
];
public function render()
{
$shouldBePublic = request()
->route()
->getName() !== 'library.table.lecturer';
return view('livewire.library.search-by-tag-component', [
'languages' => LibraryItem::query()
->pluck('language_code')
->unique()
->sort()
->map(fn ($item) => str($item)
->before('_')
->toString())
->values()
->toArray(),
'tags' => Tag::query()
->with([
'libraryItems.libraries',
'libraryItems.lecturer',
])
->withCount([
'libraryItems',
])
->where('type', 'library_item')
->whereHas('libraryItems.libraries',
fn ($query) => $query->where('is_public', $shouldBePublic))
->orderByDesc('library_items_count')
->orderBy('tags.id')
->get(),
]);
}
}

View File

@@ -1,46 +0,0 @@
<?php
namespace App\Http\Livewire\Meetup\Embed;
use App\Models\Country;
use App\Models\Meetup;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class CountryMap extends Component
{
public Country $country;
public bool $darkMode = false;
protected $queryString = ['darkMode' => ['except' => false]];
public function render()
{
return view('livewire.meetup.embed.country-map', [
'markers' => Meetup::query()
->with([
'city.country',
])
->whereHas('city.country',
fn($query) => $query->where('countries.code', $this->country->code))
->get()
->map(fn($meetup) => [
'id' => $meetup->id,
'name' => $meetup->name,
'coords' => [$meetup->city->latitude, $meetup->city->longitude],
'url' => url()->route('meetup.landing', [
'country' => $meetup->city->country->code,
'meetup' => $meetup,
]),
]),
])->layout('layouts.app', [
'darkModeDisabled' => !$this->darkMode,
'SEOData' => new SEOData(
title: __('Meetups'),
description: __('Bitcoiner Meetups are a great way to meet other Bitcoiners in your area. You can learn from each other, share ideas, and have fun!'),
image: asset('img/screenshot.png')
),
]);
}
}

View File

@@ -1,174 +0,0 @@
<?php
namespace App\Http\Livewire\Meetup\Form;
use App\Models\MeetupEvent;
use App\Support\Carbon;
use Livewire\Component;
use WireUi\Traits\Actions;
class MeetupEventForm extends Component
{
use Actions;
public string $country;
public ?MeetupEvent $meetupEvent = null;
public bool $recurring = false;
public int $repetitions = 12;
public array $series = [];
public ?string $fromUrl = '';
protected $queryString = ['fromUrl' => ['except' => '']];
public function rules()
{
return [
'meetupEvent.meetup_id' => 'required',
'meetupEvent.start' => 'required',
'meetupEvent.location' => 'string|max:255|nullable',
'meetupEvent.description' => 'string|nullable',
'meetupEvent.link' => 'url|max:255|nullable',
'series' => 'array',
'series.*.start' => 'required',
'recurring' => 'bool',
'repetitions' => 'numeric|min:1',
];
}
public function mount()
{
if (!$this->meetupEvent) {
$this->meetupEvent = new MeetupEvent(
[
'start' => now()
->startOfDay()
->addHours(17),
]
);
} elseif (!auth()
->user()
->can('update', $this->meetupEvent)) {
abort(403);
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
}
public function updatedMeetupEventStart($value)
{
$this->validateOnly('meetupEvent.start');
if ($this->recurring) {
$this->updatedRecurring(true);
}
}
public function updatedRecurring($value)
{
$this->validateOnly('recurring');
$series = [];
if ($value && $this->meetupEvent->start) {
for ($i = 0; $i < $this->repetitions; $i++) {
$series[] = [
'start' => $this->meetupEvent->start->addMonths($i + 1)
->toDateTimeString(),
];
}
}
$this->series = $series;
}
public function updatedRepetitions($value)
{
$this->validateOnly('repetitions');
if ($this->recurring) {
$this->updatedRecurring(true, $value);
}
}
public function deleteMe()
{
$this->dialog()
->confirm(
[
'title' => __('Delete event'),
'description' => __('Are you sure you want to delete this event? This action cannot be undone.'),
'icon' => 'warning',
'accept' => [
'label' => __('Yes, delete'),
'method' => 'deleteEvent',
],
'reject' => [
'label' => __('No, cancel'),
'method' => 'cancel',
],
]
);
}
public function deleteEvent()
{
$this->meetupEvent->delete();
return to_route('meetup.table.meetupEvent', ['country' => $this->country]);
}
public function submit()
{
$this->validate();
if (!$this->meetupEvent->id) {
$hasAppointmentsOnThisDate = MeetupEvent::query()
->where('meetup_id', $this->meetupEvent->meetup_id)
->where('start', '>', Carbon::parse($this->meetupEvent->start)
->startOfDay())
->where('start', '<', Carbon::parse($this->meetupEvent->start)
->endOfDay())
->exists();
if ($hasAppointmentsOnThisDate) {
$this->notification()
->warning(__('There is already an event on this date. Please choose another date or delete the existing events.'));
return;
}
}
$this->meetupEvent->save();
if ($this->recurring) {
foreach ($this->series as $event) {
$hasAppointmentsOnThisDate = MeetupEvent::query()
->where('meetup_id', $this->meetupEvent->meetup_id)
->where('start', '>', Carbon::parse($event['start'])
->startOfDay())
->where('start', '<', Carbon::parse($event['start'])
->endOfDay())
->exists();
if ($hasAppointmentsOnThisDate) {
continue;
}
$this->meetupEvent->replicate()
->fill($event)
->saveQuietly();
}
}
$this->notification()
->success(__('Event saved successfully.'));
return to_route('meetup.table.meetupEvent', ['country' => $this->country]);
}
public function render()
{
return view('livewire.meetup.form.meetup-event-form');
}
}

View File

@@ -1,93 +0,0 @@
<?php
namespace App\Http\Livewire\Meetup\Form;
use App\Models\Meetup;
use Illuminate\Validation\Rule;
use Livewire\Component;
use Livewire\WithFileUploads;
use WireUi\Traits\Actions;
class MeetupForm extends Component
{
use WithFileUploads;
use Actions;
public string $country;
public ?Meetup $meetup = null;
public ?string $fromUrl = '';
public $image;
protected $queryString = [
'fromUrl' => [
'except' => null,
],
];
public function rules()
{
return [
'image' => [Rule::requiredIf(!$this->meetup->id), 'nullable', 'mimes:jpeg,png,jpg,gif', 'max:10240'],
'meetup.city_id' => 'required',
'meetup.name' => [
'required',
Rule::unique('meetups', 'name')
->ignore($this->meetup),
],
'meetup.community' => 'required',
'meetup.telegram_link' => 'string|nullable|required_without_all:meetup.webpage,meetup.nostr,meetup.twitter_username,meetup.matrix_group',
'meetup.intro' => 'string|nullable',
'meetup.webpage' => 'string|url|nullable|required_without_all:meetup.telegram_link,meetup.nostr,meetup.twitter_username,meetup.matrix_group',
'meetup.nostr' => 'string|nullable|required_without_all:meetup.webpage,meetup.telegram_link,meetup.twitter_username,meetup.matrix_group',
'meetup.twitter_username' => 'string|regex:/^[A-z0-9!@]+$/|nullable|required_without_all:meetup.webpage,meetup.telegram_link,meetup.nostr,meetup.matrix_group',
'meetup.matrix_group' => 'string|nullable|required_without_all:meetup.webpage,meetup.telegram_link,meetup.nostr,meetup.twitter_username',
'meetup.simplex' => 'string|nullable',
];
}
public function mount()
{
if (!$this->meetup) {
$this->meetup = new Meetup([
'community' => 'einundzwanzig',
]);
} elseif (
!auth()
->user()
->can('update', $this->meetup)
) {
abort(403);
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
}
public function submit()
{
$this->validate();
$this->meetup->save();
if ($this->image) {
$this->meetup->addMedia($this->image)
->usingFileName(md5($this->image->getClientOriginalName()) . '.' . $this->image->getClientOriginalExtension())
->toMediaCollection('logo');
}
auth()
->user()
->meetups()
->syncWithoutDetaching($this->meetup->id);
return redirect($this->fromUrl);
}
public function render()
{
return view('livewire.meetup.form.meetup-form');
}
}

View File

@@ -1,68 +0,0 @@
<?php
namespace App\Http\Livewire\Meetup;
use App\Models\Country;
use App\Models\Meetup;
use App\Models\MeetupEvent;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class LandingPage extends Component
{
public Meetup $meetup;
public Country $country;
public ?int $activeEvent = null;
public ?int $year = null;
public function mount()
{
$this->meetup->load([
'media',
]);
}
public function render()
{
return view('livewire.meetup.landing-page', [
'meetupEvents' => MeetupEvent::query()
->with([
'meetup.city.country',
])
->where('meetup_events.meetup_id', $this->meetup->id)
->where('meetup_events.start', '>=', now()->subDay())
->orderBy('start')
->get(),
'events' => MeetupEvent::query()
->with([
'meetup.city.country',
])
->where('meetup_events.meetup_id', $this->meetup->id)
->where('meetup_events.start', '>=', now()->subDay())
->orderBy('start')
->get()
->map(fn ($event) => [
'id' => $event->id,
'startDate' => $event->start,
'endDate' => $event->start->addHours(1),
'location' => $event->location,
'description' => $event->description,
]),
])
->layout('layouts.guest', [
'SEOData' => new SEOData(
title: $this->meetup->name,
description: __('Bitcoiner Meetups are a great way to meet other Bitcoiners in your area. You can learn from each other, share ideas, and have fun!'),
image: $this->meetup->getFirstMediaUrl('logo'),
),
]);
}
public function showEvent($id)
{
$this->activeEvent = $id;
}
}

View File

@@ -1,209 +0,0 @@
<?php
namespace App\Http\Livewire\Meetup;
use App\Models\Country;
use App\Models\Meetup;
use App\Models\MeetupEvent;
use App\Models\User;
use App\Rules\UniqueAttendeeName;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class LandingPageEvent extends Component
{
public MeetupEvent $meetupEvent;
public Country $country;
public ?Meetup $meetup = null;
public bool $willShowUp = false;
public bool $perhapsShowUp = false;
public string $name = '';
public array $attendees = [];
public array $mightAttendees = [];
public function rules()
{
return [
'name' => [
'required',
new UniqueAttendeeName($this->meetupEvent),
],
];
}
public function mount()
{
$this->meetupEvent->load('meetup.users');
$this->meetup = $this->meetupEvent->meetup;
$this->name = auth()->check() ? auth()->user()->name : '';
$this->checkShowUp();
}
public function checkShowUp()
{
$attendees = collect($this->meetupEvent->attendees);
$mightAttendees = collect($this->meetupEvent->might_attendees);
if (auth()->check() && $attendees->contains(fn($value) => str($value)->contains('id_'.auth()->id()))) {
$this->name = str($attendees->filter(fn($value) => str($value)->contains('id_'.auth()->id()))
->first())
->after('|')
->toString();
$this->willShowUp = true;
}
if (!auth()->check() && $attendees->contains(fn($value) => str($value)->contains('anon_'.session()->getId()))) {
$this->name = str($attendees->filter(fn($value) => str($value)->contains('anon_'.session()->getId()))
->first())
->after('|')
->toString();
$this->willShowUp = true;
}
if (auth()->check() && $mightAttendees->contains(fn($value) => str($value)->contains('id_'.auth()->id()))) {
$this->name = str($mightAttendees->filter(fn($value) => str($value)->contains('id_'.auth()->id()))
->first())
->after('|')
->toString();
$this->perhapsShowUp = true;
}
if (!auth()->check() && $mightAttendees->contains(fn($value
) => str($value)->contains('anon_'.session()->getId()))) {
$this->name = str($mightAttendees->filter(fn($value) => str($value)->contains('anon_'.session()->getId()))
->first())
->after('|')
->toString();
$this->perhapsShowUp = true;
}
$this->attendees = $this->mapAttendees($attendees);
$this->mightAttendees = $this->mapAttendees($mightAttendees);
}
private function mapAttendees($collection) {
return $collection->map(function ($value) {
if (str($value)->contains('anon_')) {
$id = -1;
} else {
$id = str($value)
->before('|')
->after('id_')
->toString();
}
return [
'id' => $id,
'user' => $id > 0 ? User::withoutEvents(static fn() => User::query()
->select([
'id',
'name',
'profile_photo_path',
])
->find($id)
?->append('profile_photo_url')
->toArray())
: null,
'name' => str($value)
->after('|')
->toString(),
];
})
->toArray();
}
public function cannotCome()
{
$attendees = collect($this->meetupEvent->attendees);
$mightAttendees = collect($this->meetupEvent->might_attendees);
if (auth()->check() && $attendees->contains(fn($value) => str($value)->contains('id_'.auth()->id()))) {
$attendees = $attendees->filter(fn($value) => !str($value)->contains('id_'.auth()->id()));
$this->willShowUp = false;
}
if (!auth()->check() && $attendees->contains(fn($value) => str($value)->contains('anon_'.session()->getId()))) {
$attendees = $attendees->filter(fn($value) => !str($value)->contains('anon_'.session()->getId()));
$this->willShowUp = false;
}
if (auth()->check() && $mightAttendees->contains(fn($value) => str($value)->contains('id_'.auth()->id()))) {
$mightAttendees = $mightAttendees->filter(fn($value) => !str($value)->contains('id_'.auth()->id()));
$this->perhapsShowUp = false;
}
if (!auth()->check() && $mightAttendees->contains(fn($value
) => str($value)->contains('anon_'.session()->getId()))) {
$mightAttendees = $mightAttendees->filter(fn($value) => !str($value)->contains('anon_'.session()->getId()));
$this->perhapsShowUp = false;
}
$this->meetupEvent->update([
'attendees' => $attendees->toArray(),
'might_attendees' => $mightAttendees->toArray(),
]);
$this->checkShowUp();
}
public function attend()
{
$this->validate();
$attendees = collect($this->meetupEvent->attendees);
if (auth()->check() && !$attendees->contains('id_'.auth()->id().'|'.$this->name)) {
$attendees->push('id_'.auth()->id().'|'.$this->name);
$this->willShowUp = true;
}
if (!auth()->check() && !$attendees->contains('anon_'.session()->getId().'|'.$this->name)) {
$attendees->push('anon_'.session()->getId().'|'.$this->name);
$this->willShowUp = true;
}
$this->meetupEvent->update([
'attendees' => $attendees->toArray(),
]);
$this->checkShowUp();
}
public function mightAttend()
{
$this->validate();
$mightAttendees = collect($this->meetupEvent->might_attendees);
if (auth()->check() && !$mightAttendees->contains('id_'.auth()->id().'|'.$this->name)) {
$mightAttendees->push('id_'.auth()->id().'|'.$this->name);
$this->perhapsShowUp = true;
}
if (!auth()->check() && !$mightAttendees->contains('anon_'.session()->getId().'|'.$this->name)) {
$mightAttendees->push('anon_'.session()->getId().'|'.$this->name);
$this->perhapsShowUp = true;
}
$this->meetupEvent->update([
'might_attendees' => $mightAttendees->toArray(),
]);
$this->checkShowUp();
}
public function render()
{
return view('livewire.meetup.landing-page-event')->layout('layouts.guest', [
'SEOData' => new SEOData(
title: $this->meetupEvent->start->asDateTime().' - '.$this->meetup->name,
description: __('Here you can confirm your participation and find more information about the Meetup.').' - '.$this->meetupEvent->description,
image: $this->meetup->getFirstMediaUrl('logo'),
),
]);
}
}

View File

@@ -1,97 +0,0 @@
<?php
namespace App\Http\Livewire\Meetup;
use App\Models\Country;
use App\Models\MeetupEvent;
use App\Traits\HasMapEmbedCodeTrait;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
use WireUi\Traits\Actions;
class MeetupEventTable extends Component
{
use Actions;
use HasMapEmbedCodeTrait;
public Country $country;
public ?int $year = null;
protected $queryString = ['year'];
public function mount()
{
if (!$this->year) {
$this->year = now()->year;
}
}
public function render()
{
return view('livewire.meetup.meetup-event-table', [
'markers' => MeetupEvent::query()
->with([
'meetup.city.country',
])
->where('meetup_events.start', '>=', now()->subDay())
->whereHas('meetup.city.country',
fn($query) => $query->where('countries.code', $this->country->code))
->get()
->map(fn($event) => [
'id' => $event->id,
'name' => $event->meetup->name . ': ' . $event->location,
'coords' => [$event->meetup->city->latitude, $event->meetup->city->longitude],
]),
'events' => MeetupEvent::query()
->with([
'meetup.city.country',
])
->where('meetup_events.start', '>=', now()->subDay())
->whereHas('meetup.city.country',
fn($query) => $query->where('countries.code', $this->country->code))
->get()
->map(fn($event) => [
'id' => $event->id,
'startDate' => $event->start,
'endDate' => $event->start->addHours(1),
'location' => $event->location,
'description' => $event->description,
]),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Meetup dates'),
description: __('List of all meetup dates'),
image: asset('img/screenshot.png')
),
]);
}
public function filterByMarker($id)
{
return to_route('meetup.table.meetupEvent', [
'#table',
'country' => $this->country->code,
'year' => $this->year,
'meetup_events' => [
'filters' => [
'byid' => $id,
],
],
]);
}
public function popover($content, $ids)
{
return to_route('meetup.table.meetupEvent', [
'#table',
'year' => $this->year,
'country' => $this->country->code,
'meetup_events' => [
'filters' => [
'byid' => $ids,
],
],
]);
}
}

View File

@@ -1,54 +0,0 @@
<?php
namespace App\Http\Livewire\Meetup;
use App\Models\Country;
use App\Models\Meetup;
use App\Traits\HasMapEmbedCodeTrait;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class MeetupTable extends Component
{
use HasMapEmbedCodeTrait;
public Country $country;
public function filterByMarker($id)
{
$meetup = Meetup::with(['city.country'])
->find($id);
return to_route('meetup.landing', [
'country' => $meetup->city->country->code,
'meetup' => $meetup,
]);
}
public function render()
{
// let markers = [{name: 'VAK', coords: [50.0091294, 9.0371812], status: 'closed', offsets: [0, 2]}];
return view('livewire.meetup.meetup-table', [
'markers' => Meetup::query()
->where('visible_on_map', true)
->with([
'city.country',
])
->whereHas('city.country',
fn($query) => $query->where('countries.code', $this->country->code))
->get()
->map(fn($meetup) => [
'id' => $meetup->id,
'name' => $meetup->name,
'coords' => [$meetup->city->latitude, $meetup->city->longitude],
]),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Meetups'),
description: __('Bitcoiner Meetups are a great way to meet other Bitcoiners in your area. You can learn from each other, share ideas, and have fun!'),
image: asset('img/screenshot.png')
),
]);
}
}

View File

@@ -1,46 +0,0 @@
<?php
namespace App\Http\Livewire\Meetup;
use App\Models\Country;
use App\Models\Meetup;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class WorldMap extends Component
{
public Country $country;
public function filterByMarker($id)
{
$meetup = Meetup::with(['city.country'])
->find($id);
return to_route('meetup.landing', [
'country' => $meetup->city->country->code,
'meetup' => $meetup,
]);
}
public function render()
{
return view('livewire.meetup.world-map', [
'allMarkers' => Meetup::query()
->where('visible_on_map', true)
->with([
'city.country',
])
->get()
->map(fn($meetup) => [
'id' => $meetup->id,
'name' => $meetup->name,
'coords' => [$meetup->city->latitude, $meetup->city->longitude],
]),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('World map of meetups'),
image: asset('img/screenshot.png')
),
]);
}
}

View File

@@ -1,103 +0,0 @@
<?php
namespace App\Http\Livewire\News;
use App\Models\LibraryItem;
use App\Traits\NostrTrait;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
use WireUi\Traits\Actions;
class ArticleOverview extends Component
{
use Actions;
use NostrTrait;
public $perPage = 9;
public array $filters = [];
protected $queryString = [
'filters' => ['except' => ''],
];
public function loadMore()
{
$this->perPage += 9;
}
public function nostr($id)
{
$libraryItem = LibraryItem::query()
->with([
'lecturer',
])
->find($id);
$libraryItem->setStatus('published');
$libraryItemName = $libraryItem->name;
if ($libraryItem->lecturer->nostr) {
$libraryItemName .= ' von @'.$libraryItem->lecturer->nostr;
} else {
$libraryItemName .= ' von '.$libraryItem->lecturer->name;
}
$text = sprintf("Ein neuer News-Artikel wurde verfasst:\n\n%s\n\n%s\n\n#Bitcoin #News #Einundzwanzig #gesundesgeld #einundzwanzig_portal_%s",
$libraryItemName,
url()->route('article.view',
['libraryItem' => $libraryItem->slug]),
str($libraryItem->slug)->replace('-', '_')
);
$result = $this->publishOnNostr($libraryItem, $text);
if ($result['success']) {
$this->notification()
->success(title: __('Published on Nostr'), description: $result['output']);
} else {
$this->notification()
->error(title: __('Failed'),
description: 'Exit Code: '.$result['exitCode'].' Reason: '.$result['errorOutput']);
}
}
public function approve($id)
{
$libraryItem = LibraryItem::find($id);
$libraryItem->approved = true;
$libraryItem->save();
$this->notification()
->success(__('Article approved'));
$this->emit('$refresh');
}
public function resetFiltering()
{
return to_route('article.overview');
}
public function render()
{
return view('livewire.news.article-overview', [
'libraryItems' => LibraryItem::query()
->with([
'createdBy.roles',
'lecturer',
'tags',
])
->when(
isset($this->filters['author']),
fn($query) => $query->whereHas('lecturer',
fn($query) => $query->where('lecturers.slug',
$this->filters['author'])))
->where('type', 'markdown_article')
->where('news', true)
->orderByDesc('created_at')
->paginate($this->perPage),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('News'),
description: __('Here we post important news that is relevant for everyone.'),
image: asset('img/einundzwanzig-news-colored.png'),
),
]);
}
}

View File

@@ -1,31 +0,0 @@
<?php
namespace App\Http\Livewire\News;
use App\Models\Lecturer;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class AuthorsOverview extends Component
{
public function render()
{
return view('livewire.news.authors-overview', [
'authors' => Lecturer::query()
->whereHas('libraryItems', function ($query) {
$query->where('library_items.news', true);
})
->withCount([
'libraryItems' => fn($query) => $query->where('library_items.news', true),
])
->orderByDesc('library_items_count')
->get(),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('News articles writer'),
description: __('Click on any of the authors to see their articles.'),
image: asset('img/einundzwanzig-news-colored.png'),
),
]);
}
}

View File

@@ -1,134 +0,0 @@
<?php
namespace App\Http\Livewire\News\Form;
use App\Models\LibraryItem;
use App\Traits\HasTagsTrait;
use Illuminate\Validation\Rule;
use Livewire\Component;
use Livewire\WithFileUploads;
class NewsArticleForm extends Component
{
use HasTagsTrait;
use WithFileUploads;
public ?LibraryItem $libraryItem = null;
public $image;
public $currentImage = 0;
public $images;
public $imagesCloned = [];
public array $temporaryUrls = [];
public ?string $fromUrl = '';
public string $type = '';
public bool $paid = false;
protected $queryString = ['fromUrl' => ['except' => ''], 'type' => ['except' => '']];
public function rules()
{
return [
'image' => [Rule::requiredIf(!$this->libraryItem->id), 'nullable', 'mimes:jpeg,png,jpg,gif', 'max:10240'],
'selectedTags' => 'array|min:1',
'libraryItem.lecturer_id' => 'required',
'libraryItem.name' => 'required',
'libraryItem.type' => 'required',
'libraryItem.language_code' => 'required',
'libraryItem.value' => 'required',
'libraryItem.value_to_be_paid' => [Rule::requiredIf($this->libraryItem->sats > 0), 'nullable', 'string',],
'libraryItem.sats' => [
Rule::requiredIf($this->libraryItem->sats > 0), 'nullable', 'numeric',
],
'libraryItem.subtitle' => 'string|nullable',
'libraryItem.excerpt' => 'required',
'libraryItem.main_image_caption' => 'string|nullable',
'libraryItem.read_time' => 'numeric|nullable',
'libraryItem.approved' => 'boolean',
'libraryItem.news' => 'boolean',
];
}
public function mount()
{
if ($this->type === 'paid') {
$this->paid = true;
}
if (!$this->libraryItem) {
$this->libraryItem = new LibraryItem([
'type' => 'markdown_article',
'value' => '',
'value_to_be_paid' => '',
'read_time' => 1,
'sats' => $this->paid ? 21 : null,
'news' => true,
'language_code' => 'de',
'approved' => false,
]);
$this->selectedTags[] = 'News';
} else {
$this->selectedTags = $this->libraryItem->tags()
->where('type', 'library_item')
->get()
->map(fn($tag) => $tag->name)
->toArray();
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
if (!$this->libraryItem->value_to_be_paid) {
$this->libraryItem->value_to_be_paid = '';
}
}
public function updatedImages($value)
{
$clonedImages = collect($this->imagesCloned);
$clonedImages = $clonedImages->push($value);
$this->imagesCloned = $clonedImages->toArray();
$temporaryUrls = collect($this->temporaryUrls);
$temporaryUrls = $temporaryUrls->push($value->temporaryUrl());
$this->temporaryUrls = $temporaryUrls->toArray();
}
public function save()
{
$this->validate();
$this->libraryItem->save();
$this->libraryItem->syncTagsWithType(
$this->selectedTags,
'library_item'
);
if ($this->image) {
$this->libraryItem->addMedia($this->image)
->usingFileName(md5($this->image->getClientOriginalName()).'.'.$this->image->getClientOriginalExtension())
->toMediaCollection('main');
}
return redirect($this->fromUrl);
}
public function delete()
{
$this->libraryItem->delete();
return redirect($this->fromUrl);
}
public function render()
{
return view('livewire.news.form.news-article-form');
}
}

View File

@@ -1,142 +0,0 @@
<?php
namespace App\Http\Livewire\News;
use App\Models\LibraryItem;
use App\Traits\LNBitsTrait;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
use Spatie\CommonMarkShikiHighlighter\HighlightCodeExtension;
use WireUi\Traits\Actions;
class InternArticleView extends Component
{
use Actions;
use LNBitsTrait;
public LibraryItem $libraryItem;
public $qrCode = '';
public $invoice = '';
public $paymentHash = '';
public $checkid = null;
public $checkThisPaymentHash = '';
public bool $invoicePaid = false;
public bool $alreadyPaid = false;
public ?string $payNymQrCode = '';
public function mount()
{
$this->libraryItem->load([
'libraries',
]);
if ($this->libraryItem->libraries->where('is_public', false)
->count() > 0 && !auth()->check()) {
abort(403, __('Sorry! You are not authorized to perform this action.'));
}
if (auth()->check() && auth()
->user()
->paidArticles()
->where('library_item_id', $this->libraryItem->id)
->count() > 0) {
$this->invoicePaid = true;
}
if ($this->libraryItem->lecturer->paynym) {
$this->payNymQrCode = base64_encode(QrCode::format('png')
->size(300)
->merge($this->libraryItem->lecturer->getFirstMedia('avatar')
? str(
$this->libraryItem
->lecturer
->getFirstMediaPath('avatar'))
->replace('/home/einundzwanzig/portal.einundzwanzig.space',
''
)
: '/public/img/einundzwanzig.png',
.3)
->errorCorrection('H')
->generate($this->libraryItem->lecturer->paynym));
}
}
public function pay()
{
try {
$invoice = $this->createInvoice(
sats: $this->libraryItem->sats,
memo: 'Payment for: "'.$this->libraryItem->slug.'" on Einundzwanzig Portal.',
lnbits: $this->libraryItem->createdBy->lnbits,
);
} catch (\Exception $e) {
$this->notification()
->error('LNBits error: '.$e->getMessage());
return;
}
session('payment_hash_article_'.$this->libraryItem->id, $invoice['payment_hash']);
$this->paymentHash = $invoice['payment_hash'];
$this->qrCode = base64_encode(QrCode::format('png')
->size(300)
->merge($this->libraryItem->lecturer->getFirstMedia('avatar')
? str(
$this->libraryItem
->lecturer
->getFirstMediaPath('avatar'))
->replace('/home/einundzwanzig/portal.einundzwanzig.space',
''
)
: '/public/img/einundzwanzig.png',
.3)
->errorCorrection('H')
->generate($invoice['payment_request']));
$this->invoice = $invoice['payment_request'];
$this->checkid = $invoice['checking_id'];
}
public function checkPaymentHash()
{
try {
$invoice = $this->check($this->checkid ?? $this->checkThisPaymentHash,
$this->libraryItem->createdBy->lnbits);
} catch (\Exception $e) {
$this->notification()
->error('LNBits error: '.$e->getMessage());
return;
}
if (isset($invoice['paid']) && $invoice['paid']) {
$this->invoicePaid = true;
if (auth()->check()) {
auth()
->user()
->paidArticles()
->syncWithoutDetaching($this->libraryItem->id);
}
} else {
Log::error(json_encode($invoice, JSON_THROW_ON_ERROR));
}
}
public function render()
{
return view('livewire.news.intern-article-view')->layout('layouts.app', [
'SEOData' => new SEOData(
title: $this->libraryItem->name,
description: strip_tags($this->libraryItem->excerpt) ?? __('Here we post important news that is relevant for everyone.'),
author: $this->libraryItem->lecturer->name,
image: $this->libraryItem->getFirstMedia('main')
? $this->libraryItem->getFirstMediaUrl('main', 'seo')
: url()->route('imgPublic', [
'path' => 'img/einundzwanzig-wallpaper-benrath.png', 'h' => 630, 'w' => 1200, 'fit' => 'crop'
]),
published_time: Carbon::parse($this->libraryItem->created_at),
type: 'article',
),
]);
}
}

View File

@@ -1,38 +0,0 @@
<?php
namespace App\Http\Livewire\Nostr;
use App\Models\User;
use Livewire\Component;
class PlebsOverview extends Component
{
public array $plebsNpubs = [];
public function mount()
{
$this->plebsNpubs = User::query()
->select([
'email',
'public_key',
'lightning_address',
'lnurl',
'node_id',
'paynym',
'lnbits',
'nostr',
'id',
])
->whereNotNull('nostr')
->orderByDesc('id')
->get()
->unique('nostr')
->pluck('nostr')
->toArray();
}
public function render()
{
return view('livewire.nostr.plebs-overview');
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Http\Livewire\Nostr;
use Livewire\Component;
class Start extends Component
{
public function render()
{
return view('livewire.nostr.start');
}
}

View File

@@ -1,57 +0,0 @@
<?php
namespace App\Http\Livewire\Profile;
use App\Traits\LNBitsTrait;
use Livewire\Component;
use WireUi\Traits\Actions;
class LNBits extends Component
{
use Actions;
use LNBitsTrait;
public array $settings = [
'url' => 'https://legend.lnbits.com',
'wallet_id' => '',
'read_key' => '',
];
public function rules()
{
return [
'settings.url' => 'required|url',
'settings.wallet_id' => 'required',
'settings.read_key' => 'required',
];
}
public function mount()
{
if (auth()->user()->lnbits) {
$this->settings = auth()->user()->lnbits;
}
}
public function save()
{
$this->validate();
if ($this->checkLnbitsSettings($this->settings['read_key'], $this->settings['url'], $this->settings['wallet_id']) === false) {
$this->notification()
->error(__('LNBits settings are not valid!'));
return;
}
$user = auth()->user();
$user->lnbits = $this->settings;
$user->save();
$this->notification()
->success(__('LNBits settings saved successfully!'));
}
public function render()
{
return view('livewire.profile.l-n-bits');
}
}

View File

@@ -1,135 +0,0 @@
<?php
namespace App\Http\Livewire\Profile;
use App\Models\Meetup;
use Livewire\Component;
use WireUi\Traits\Actions;
class Meetups extends Component
{
use Actions;
public $search = '';
public $meetups;
public $myMeetups = [];
public $myMeetupNames = [];
public $hasMeetups = false;
public ?string $fromUrl = '';
protected $queryString = ['fromUrl' => ['except' => '']];
public function rules()
{
return [
'search' => 'string',
];
}
public function mount()
{
if (!auth()->user()) {
return to_route('auth.login');
}
$this->meetups = Meetup::query()
->with([
'city',
])
->where('name', 'ilike', '%'.$this->search.'%')
->orderBy('name')
->limit(10)
->get();
$this->myMeetups = auth()
->user()
->meetups()
->pluck('meetup_id')
->toArray();
$this->myMeetupNames = auth()
->user()
->meetups()
->with([
'city.country'
])
->select('meetups.id', 'meetups.city_id', 'meetups.name', 'meetups.slug')
->get()
->map(fn($meetup) => [
'id' => $meetup->id,
'name' => $meetup->name,
'link' => route('meetup.landing', [
'country' => $meetup->city->country->code,
'meetup' => $meetup,
])
])
->toArray();
if (count($this->myMeetups) > 0) {
$this->hasMeetups = true;
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
}
public function next()
{
return redirect($this->fromUrl);
}
public function updatedSearch($value)
{
$this->meetups = Meetup::query()
->with([
'city',
])
->where('name', 'ilike', '%'.$value.'%')
->orderBy('name')
->limit(10)
->get();
}
public function signUpForMeetup($id)
{
$user = auth()->user();
$user->meetups()
->toggle($id);
$this->myMeetups = auth()
->user()
->meetups()
->pluck('meetup_id')
->toArray();
if (count($this->myMeetups) > 0) {
$this->hasMeetups = true;
} else {
$this->hasMeetups = false;
}
$this->myMeetupNames = auth()
->user()
->meetups()
->with([
'city.country'
])
->select('meetups.id', 'meetups.city_id', 'meetups.name', 'meetups.slug')
->get()
->map(fn($meetup) => [
'id' => $meetup->id,
'name' => $meetup->name,
'link' => route('meetup.landing', [
'country' => $meetup->city->country->code,
'meetup' => $meetup,
])
])
->toArray();
$this->notification()
->success(__('Saved.'));
}
public function render()
{
return view('livewire.profile.meetups');
}
}

View File

@@ -1,73 +0,0 @@
<?php
namespace App\Http\Livewire\ProjectProposal\Form;
use App\Models\Country;
use App\Models\ProjectProposal;
use Livewire\Component;
use Livewire\WithFileUploads;
class ProjectProposalForm extends Component
{
use WithFileUploads;
public Country $country;
public ?ProjectProposal $projectProposal = null;
public $image;
public ?string $fromUrl = '';
protected $queryString = [
'fromUrl' => ['except' => ''],
];
public function rules()
{
return [
'image' => [
'nullable', 'mimes:jpeg,png,jpg,gif', 'max:10240'
],
'projectProposal.user_id' => 'required',
'projectProposal.name' => 'required',
'projectProposal.support_in_sats' => 'required|numeric',
'projectProposal.description' => 'required',
];
}
public function mount()
{
if (!$this->projectProposal) {
$this->projectProposal = new ProjectProposal([
'user_id' => auth()->id(),
'description' => '',
]);
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
}
public function save()
{
$this->validate();
$this->projectProposal->save();
if ($this->image) {
$this->projectProposal->addMedia($this->image)
->usingFileName(md5($this->image->getClientOriginalName()).'.'.$this->image->getClientOriginalExtension())
->toMediaCollection('main');
}
return redirect($this->fromUrl);
}
public function render()
{
return view('livewire.project-proposal.form.project-proposal-form', [
]);
}
}

View File

@@ -1,23 +0,0 @@
<?php
namespace App\Http\Livewire\ProjectProposal;
use App\Models\Country;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class ProjectProposalTable extends Component
{
public Country $country;
public function render()
{
return view('livewire.project-proposal.project-proposal-table')->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Project Proposal'),
description: __('Submit a project proposal and let the community vote on it through the elected voters. All other community members can also vote.'),
image: asset('img/voting.jpg')
),
]);
}
}

View File

@@ -1,115 +0,0 @@
<?php
namespace App\Http\Livewire\ProjectProposal;
use App\Models\Country;
use App\Models\ProjectProposal;
use App\Models\User;
use App\Models\Vote;
use Illuminate\Validation\Rule;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class ProjectProposalVoting extends Component
{
public ?ProjectProposal $projectProposal = null;
public ?Vote $vote = null;
public ?string $fromUrl = '';
protected $queryString = [
'fromUrl' => ['except' => ''],
];
public function rules()
{
return [
'vote.user_id' => 'required',
'vote.project_proposal_id' => 'required',
'vote.value' => 'required|boolean',
'vote.reason' => [
Rule::requiredIf(!$this->vote->value),
]
];
}
public function mount()
{
$this->projectProposal->load('votes');
$vote = Vote::query()
->where('user_id', auth()->id())
->where('project_proposal_id', $this->projectProposal->id)
->first();
if ($vote) {
$this->vote = $vote;
} else {
$this->vote = new Vote();
$this->vote->user_id = auth()->id();
$this->vote->project_proposal_id = $this->projectProposal->id;
$this->vote->value = false;
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
}
public function yes()
{
$this->vote->value = true;
$this->vote->save();
return to_route('voting.projectFunding',
['projectProposal' => $this->projectProposal, 'fromUrl' => $this->fromUrl]);
}
public function no()
{
$this->validate();
$this->vote->value = false;
$this->vote->save();
return to_route('voting.projectFunding',
['projectProposal' => $this->projectProposal, 'fromUrl' => $this->fromUrl]);
}
public function render()
{
return view('livewire.project-proposal.project-proposal-voting', [
'entitledVoters' => User::query()
->with([
'votes' => fn($query) => $query->where('project_proposal_id',
$this->projectProposal->id)
])
->withCount([
'votes' => fn($query) => $query->where('project_proposal_id',
$this->projectProposal->id)
])
->whereHas('roles', function ($query) {
return $query->where('roles.name', 'entitled-voter');
})
->orderByDesc('votes_count')
->get(),
'otherVoters' => User::query()
->with([
'votes' => fn($query) => $query->where('project_proposal_id',
$this->projectProposal->id)
])
->withCount([
'votes' => fn($query) => $query->where('project_proposal_id',
$this->projectProposal->id)
])
->whereDoesntHave('roles', function ($query) {
return $query->where('roles.name', 'entitled-voter');
})
->orderByDesc('votes_count')
->get(),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Project Proposal'),
description: __('Submit a project proposal and let the community vote on it through the elected voters. All other community members can also vote.'),
image: asset('img/voting.jpg')
),
]);
}
}

View File

@@ -1,23 +0,0 @@
<?php
namespace App\Http\Livewire\School;
use App\Models\Country;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class CityTable extends Component
{
public Country $country;
public function render()
{
return view('livewire.school.city-table')->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Courses'),
description: __('Choose your city, search for courses in the surrounding area and select a topic that suits you.'),
image: asset('img/screenshot.png')
),
]);
}
}

View File

@@ -1,23 +0,0 @@
<?php
namespace App\Http\Livewire\School;
use App\Models\Country;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class CourseTable extends Component
{
public Country $country;
public function render()
{
return view('livewire.school.course-table')->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Courses'),
description: __('Choose your city, search for courses in the surrounding area and select a topic that suits you.'),
image: asset('img/screenshot.png')
),
]);
}
}

View File

@@ -1,94 +0,0 @@
<?php
namespace App\Http\Livewire\School;
use App\Models\Country;
use App\Models\CourseEvent;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class EventTable extends Component
{
public Country $country;
public ?int $year = null;
protected $queryString = ['year'];
public function mount()
{
if (! $this->year) {
$this->year = now()->year;
}
}
public function render()
{
return view('livewire.school.event-table', [
'markers' => CourseEvent::query()
->with([
'course',
'venue.city.country',
])
->where('from', '>=', now())
->where(fn ($query) => $query
->whereHas('venue.city.country',
fn ($query) => $query->where('countries.code', $this->country->code))
)
->get()
->map(fn ($event) => [
'id' => $event->id,
'name' => $event->course->name,
'coords' => [$event->venue->city->latitude, $event->venue->city->longitude],
]),
'events' => CourseEvent::query()
->with([
'course',
'venue.city.country',
])
->where('from', '>=', now())
->get()
->map(fn ($event) => [
'id' => $event->id,
'startDate' => $event->from,
'endDate' => $event->to,
'location' => $event->course->name,
'description' => $event->venue->name,
]),
])->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Dates'),
description: __('Dates for courses about Bitcoin.'),
image: asset('img/screenshot.png')
),
]);
}
public function filterByMarker($id)
{
return to_route('school.table.event', [
'#table',
'country' => $this->country->code,
'year' => $this->year,
'course_events' => [
'filters' => [
'byid' => $id,
],
],
]);
}
public function popover($content, $ids)
{
return to_route('school.table.event', [
'#table',
'country' => $this->country->code,
'year' => $this->year,
'course_events' => [
'filters' => [
'byid' => $ids,
],
],
]);
}
}

View File

@@ -1,67 +0,0 @@
<?php
namespace App\Http\Livewire\School\Form;
use App\Models\Course;
use App\Models\CourseEvent;
use Livewire\Component;
use Livewire\WithFileUploads;
use WireUi\Traits\Actions;
class CourseEventForm extends Component
{
use WithFileUploads;
use Actions;
public ?CourseEvent $courseEvent = null;
public ?string $fromUrl = '';
public $image;
protected $queryString = [
'fromUrl' => [
'except' => null,
],
];
public function rules()
{
return [
'courseEvent.course_id' => 'required',
'courseEvent.venue_id' => 'required',
'courseEvent.from' => 'required',
'courseEvent.to' => 'required',
'courseEvent.link' => 'required',
];
}
public function mount()
{
if (!$this->courseEvent) {
$this->courseEvent = new CourseEvent([]);
} elseif (
!auth()
->user()
->can('update', $this->courseEvent)
) {
abort(403);
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
}
public function submit()
{
$this->validate();
$this->courseEvent->save();
return redirect($this->fromUrl);
}
public function render()
{
return view('livewire.school.form.course-event-form');
}
}

View File

@@ -1,109 +0,0 @@
<?php
namespace App\Http\Livewire\School\Form;
use App\Models\Course;
use App\Models\Tag;
use Illuminate\Validation\Rule;
use Livewire\Component;
use Livewire\WithFileUploads;
use WireUi\Traits\Actions;
class CourseForm extends Component
{
use WithFileUploads;
use Actions;
public ?Course $course = null;
public ?string $fromUrl = '';
public $image;
public array $selectedTags = [];
protected $queryString = [
'fromUrl' => [
'except' => null,
],
];
public function rules()
{
return [
'image' => [Rule::requiredIf(!$this->course->id), 'nullable', 'mimes:jpeg,png,jpg,gif', 'max:10240'],
'course.lecturer_id' => 'required',
'course.name' => [
'required',
Rule::unique('courses', 'name')
->ignore($this->course),
],
'course.description' => 'string|nullable',
];
}
public function mount()
{
if (!$this->course) {
$this->course = new Course([
'description' => '',
]);
} elseif (
!auth()
->user()
->can('update', $this->course)
) {
abort(403);
} else {
$this->selectedTags = $this->course->tags()
->where('type', 'course')
->get()
->map(fn($tag) => $tag->name)
->toArray();
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
}
public function submit()
{
$this->validate();
$this->course->save();
$this->course->syncTagsWithType(
$this->selectedTags,
'course'
);
if ($this->image) {
$this->course->addMedia($this->image)
->usingFileName(md5($this->image->getClientOriginalName()).'.'.$this->image->getClientOriginalExtension())
->toMediaCollection('logo');
}
return redirect($this->fromUrl);
}
public function selectTag($name)
{
$selectedTags = collect($this->selectedTags);
if ($selectedTags->contains($name)) {
$selectedTags = $selectedTags->filter(fn($tag) => $tag !== $name);
} else {
$selectedTags->push($name);
}
$this->selectedTags = $selectedTags->values()
->toArray();
}
public function render()
{
return view('livewire.school.form.course-form', [
'tags' => Tag::query()
->where('type', 'course')
->get(),
]);
}
}

View File

@@ -1,67 +0,0 @@
<?php
namespace App\Http\Livewire\School;
use App\Models\Country;
use App\Models\CourseEvent;
use App\Models\Lecturer;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class LecturerLandingPage extends Component
{
public Lecturer $lecturer;
public Country $country;
public ?int $year = null;
public ?int $activeEvent = null;
public function render()
{
return view('livewire.school.lecturer-landing-page', [
'courseEvents' => CourseEvent::query()
->with([
'venue.city',
'course.tags',
])
->where('from', '>=', now())
->whereHas('course', function ($query) {
$query->where('lecturer_id', $this->lecturer->id);
})
->orderBy('from')
->get(),
'events' => CourseEvent::query()
->with([
'venue',
'course',
])
->where('from', '>=', now())
->whereHas('course', function ($query) {
$query->where('lecturer_id', $this->lecturer->id);
})
->orderBy('from')
->get()
->map(fn($event) => [
'id' => $event->id,
'startDate' => $event->from,
'endDate' => $event->to,
'location' => $event->course->name,
'description' => $event->venue->name,
]),
])
->layout('layouts.guest', [
'SEOData' => new SEOData(
title: $this->lecturer->name,
description: $this->lecturer->intro ?? __('This lecturer has not yet written an introduction.'),
image: $this->lecturer->getFirstMediaUrl('avatar'),
),
]);
}
public function showEvent($id)
{
$this->activeEvent = $id;
}
}

View File

@@ -1,23 +0,0 @@
<?php
namespace App\Http\Livewire\School;
use App\Models\Country;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class LecturerTable extends Component
{
public Country $country;
public function render()
{
return view('livewire.school.lecturer-table')->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Lecturers'),
description: __('Lecturers in the surrounding area.'),
image: asset('img/screenshot.png')
),
]);
}
}

View File

@@ -1,32 +0,0 @@
<?php
namespace App\Http\Livewire\School;
use App\Models\Tag;
use Livewire\Component;
class SearchByTagComponent extends Component
{
public string $country = 'de';
public ?array $courses = [];
protected $queryString = [
'courses',
];
public function render()
{
return view('livewire.school.search-by-tag-component', [
'tags' => Tag::query()
->where('type', 'course')
->with([
'courses.lecturer',
])
->withCount([
'courses',
])
->get(),
]);
}
}

View File

@@ -1,27 +0,0 @@
<?php
namespace App\Http\Livewire\School;
use App\Models\Country;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class VenueTable extends Component
{
public Country $country;
public bool $manage = false;
protected $queryString = ['manage' => ['except' => false]];
public function render()
{
return view('livewire.school.venue-table')->layout('layouts.app', [
'SEOData' => new SEOData(
title: __('Venues'),
description: __('Venues in the surrounding area.'),
image: asset('img/screenshot.png')
),
]);
}
}

View File

@@ -1,21 +0,0 @@
<?php
namespace App\Http\Livewire\Specials;
use Livewire\Component;
use RalphJSmit\Laravel\SEO\Support\SEOData;
class BalticSeaCircle extends Component
{
public function render()
{
return view('livewire.specials.baltic-sea-circle')
->layout('layouts.guest', [
'SEOData' => new SEOData(
title: 'Baltic Sea Circle Rally Bitcoin Team 218',
description: 'Besucht das Bitcoin Team 218 von Daktari und Cercatrova zum Start der diesjährigen Baltic Sea Circle Rally',
image: asset('img/bsc/3.jpg'),
),
]);
}
}

View File

@@ -1,107 +0,0 @@
<?php
namespace App\Http\Livewire\Tables;
use App\Models\BitcoinEvent;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use Rappasoft\LaravelLivewireTables\Views\Filters\TextFilter;
class BitcoinEventTable extends DataTableComponent
{
public string $country;
public string $tableName = 'bitcoin_events';
public function configure(): void
{
$this->setPrimaryKey('id')
->setDefaultSort('from', 'asc')
->setAdditionalSelects([
'bitcoin_events.id',
'bitcoin_events.venue_id',
'bitcoin_events.created_by',
])
->setThAttributes(function (Column $column) {
return [
'class' => 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider dark:bg-gray-800 dark:text-gray-400',
'default' => false,
];
})
->setTdAttributes(function (Column $column, $row, $columnIndex, $rowIndex) {
return [
'class' => 'px-6 py-4 text-sm font-medium dark:text-white',
'default' => false,
];
})
->setColumnSelectStatus(false)
->setPerPage(10)
->setConfigurableAreas([
'toolbar-left-end' => [
'columns.bitcoin_events.areas.toolbar-left-end', [
'country' => $this->country,
],
],
]);
}
public function filters(): array
{
return [
TextFilter::make('Event by ID', 'byid')
->hiddenFromMenus()
->filter(function (Builder $builder, string $value) {
$builder->whereIn('bitcoin_events.id', str($value)->explode(','));
}),
];
}
public function columns(): array
{
return [
Column::make(__('Country'), 'venue.city.country.name')
->format(
fn ($value, $row, Column $column) => view('columns.bitcoin_events.country')->withRow($row)
)
->sortable()
->collapseOnMobile(),
Column::make(__('Title'), 'title')
->format(
fn ($value, $row, Column $column) => view('columns.bitcoin_events.title')->withRow($row)
)
->sortable(),
Column::make(__('From'), 'from')
->format(
fn ($value, $row, Column $column) => $value->asDateTime()
),
Column::make(__('To'), 'to')
->format(
fn ($value, $row, Column $column) => $value->asDateTime()
)
->collapseOnMobile(),
Column::make(__('Venue'), 'venue.name')
->collapseOnMobile(),
Column::make(__('Link'), 'link')
->format(
fn ($value, $row, Column $column) => view('columns.bitcoin_events.link')->withRow($row)
)
->sortable()
->collapseOnMobile(),
];
}
public function builder(): Builder
{
return BitcoinEvent::query()
->with([
'venue.city.country',
])
->where('bitcoin_events.from', '>=', now())
->where(fn ($query) => $query
->whereHas('venue.city.country',
fn ($query) => $query->where('code', $this->country))
->orWhere('show_worldwide', true)
);
}
}

View File

@@ -1,122 +0,0 @@
<?php
namespace App\Http\Livewire\Tables;
use App\Models\BookCase;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use Rappasoft\LaravelLivewireTables\Views\Filters\TextFilter;
use WireUi\Traits\Actions;
class BookCaseTable extends DataTableComponent
{
use Actions;
public string $country;
public string $tableName = 'bookcases';
public function configure(): void
{
$this->setPrimaryKey('id')
->setAdditionalSelects(['id', 'homepage'])
->setThAttributes(function (Column $column) {
return [
'class' => 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider dark:bg-gray-800 dark:text-gray-400',
'default' => false,
];
})
->setTdAttributes(function (Column $column, $row, $columnIndex, $rowIndex) {
return [
'class' => 'px-6 py-4 text-sm font-medium dark:text-white',
'default' => false,
];
})
->setColumnSelectStatus(false)
->setPerPage(10);
}
public function filters(): array
{
return [
TextFilter::make('By IDs', 'byids')
->hiddenFromMenus()
->filter(function (Builder $builder, string $value) {
$builder->whereIn('id', str($value)->explode(','));
}),
];
}
public function columns(): array
{
return [
Column::make('Name', 'title')
->sortable()
->searchable(
function (Builder $query, $searchTerm) {
$query->where('title', 'ilike', '%'.$searchTerm.'%');
}
),
Column::make('Adresse', 'address')
->sortable()
->searchable(),
Column::make('Bitcoin-Bücher')
->label(
fn (
$row,
Column $column
) => $row->orangePills->sum('amount')
)
->collapseOnMobile(),
Column::make('Letzter Input')
->label(
fn (
$row,
Column $column
) => $row->orangePills()
->latest()
->first()?->date->asDate()
)
->collapseOnMobile(),
Column::make('Link')
->label(
fn (
$row,
Column $column
) => $row->homepage ? '<a target="_blank" class="underline text-amber-500" href="'.$this->url_to_absolute($row->homepage).'">Link</a>' : null
)
->html()
->collapseOnMobile(),
Column::make('Orange-Pilled', 'orange_pilled')
->label(fn ($row, Column $column) => view('columns.book_cases.oranged-pilled')
->withRow($row)
->withCountry($this->country))
->collapseOnMobile(),
];
}
private function url_to_absolute($url)
{
if (str($url)->contains('http')) {
return $url;
}
if (! str($url)->contains('http')) {
return str($url)->prepend('https://');
}
}
public function builder(): Builder
{
return BookCase::query()
->active()
->with([
'orangePills',
])
->withCount([
'orangePills',
])
->orderByDesc('orange_pills_count')
->orderBy('book_cases.id');
}
}

View File

@@ -1,140 +0,0 @@
<?php
namespace App\Http\Livewire\Tables;
use App\Models\BookCase;
use App\Models\City;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use WireUi\Traits\Actions;
class CityTable extends DataTableComponent
{
use Actions;
public string $country;
public string $type;
public bool $manage = false;
public string $tableName = 'cities';
public function configure(): void
{
$this->setPrimaryKey('id')
->setAdditionalSelects(['cities.id', 'cities.created_by'])
->setThAttributes(function (Column $column) {
return [
'class' => 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider dark:bg-gray-800 dark:text-gray-400',
'default' => false,
];
})
->setTdAttributes(function (Column $column, $row, $columnIndex, $rowIndex) {
return [
'class' => 'px-6 py-4 text-sm font-medium dark:text-white',
'default' => false,
];
})
->setColumnSelectStatus(false)
->setPerPage(10)
->setConfigurableAreas([
'toolbar-left-end' => [
'columns.cities.areas.toolbar-left-end', [
'country' => $this->country,
],
],
]);
}
public function columns(): array
{
$columns = collect([
Column::make('Stadt Name', 'name')
->sortable()
->searchable(fn ($builder, $term) => $builder->where('cities.name', 'ilike', '%'.$term.'%')),
]);
if ($this->type === 'school') {
$columns = $columns->merge([
Column::make('Veranstaltungs-Orte')
->label(
fn ($row, Column $column) => $row->venues_count
)
->collapseOnMobile(),
Column::make('Termine')
->label(
fn ($row, Column $column) => $row->course_events_count
)
->collapseOnMobile(),
]);
}
return $columns->merge([
Column::make('')
->label(
fn ($row, Column $column) => view('columns.cities.action')
->withRow($row)
->withType($this->type)
->withManage($this->manage)
),
])
->toArray();
}
public function builder(): Builder
{
return City::query()
->withCount([
'venues',
'courseEvents',
])
->whereHas('country', fn ($query) => $query->where('code', $this->country))
->orderByDesc('course_events_count')
->orderBy('cities.id');
}
public function proximitySearch($id)
{
$city = City::query()
->find($id);
$query = City::radius($city->latitude, $city->longitude, 100)
->where('id', '!=', $id);
return to_route('school.table.event', [
'#table',
'country' => $this->country,
'course_events' => [
'filters' => [
'stadt' => $query->pluck('name')
->push($city->name)
->implode(','),
],
],
]);
}
public function proximitySearchForBookCases($id)
{
$city = City::query()
->find($id);
$query = BookCase::active()->radius($city->latitude, $city->longitude, 25);
$ids = $query->pluck('id');
if ($ids->isEmpty()) {
$this->notification()
->error(__('No bookcases found in the radius of 5km'));
return;
}
return to_route('bookCases.table.bookcases', [
'#table',
'country' => $this->country,
'bookcases' => [
'filters' => [
'byids' => $ids->implode(','),
],
],
]);
}
}

View File

@@ -1,122 +0,0 @@
<?php
namespace App\Http\Livewire\Tables;
use App\Models\Course;
use App\Models\Tag;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectFilter;
class CourseTable extends DataTableComponent
{
public string $country;
public string $tableName = 'courses';
public function configure(): void
{
$this->setPrimaryKey('id')
->setAdditionalSelects(['courses.id', 'courses.created_by'])
->setThAttributes(function (Column $column) {
return [
'class' => 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider dark:bg-gray-800 dark:text-gray-400',
'default' => false,
];
})
->setTdAttributes(function (Column $column, $row, $columnIndex, $rowIndex) {
return [
'class' => 'px-6 py-4 text-sm font-medium dark:text-white',
'default' => false,
];
})
->setColumnSelectStatus(false)
->setPerPage(10)
->setConfigurableAreas([
'toolbar-left-end' => [
'columns.courses.areas.toolbar-left-end', [
'country' => $this->country,
],
],
]);
}
public function filters(): array
{
return [
MultiSelectFilter::make('Tag')
->options(
Tag::query()
->withType('course')
->get()
->mapWithKeys(fn ($item, $key) => [$item->name => $item->name])
->toArray()
)
->filter(function (Builder $builder, array $values) {
$builder->withAnyTags($values, 'course');
}),
];
}
public function columns(): array
{
return [
Column::make('Dozent', 'lecturer.name')
->label(
fn ($row, Column $column) => view('columns.courses.lecturer')->withRow($row)
)
->sortable()
->collapseOnMobile(),
Column::make('Name', 'name')
->searchable(fn (Builder $query, string $term) => $query->where('name', 'ilike', '%'.$term.'%'))
->sortable(),
Column::make('Tags')
->label(
fn ($row, Column $column) => view('columns.courses.tags')->withRow($row)
)
->collapseOnMobile(),
Column::make('Termine')
->label(
fn ($row, Column $column) => '<strong>'.$row->course_events_count.'</strong>'
)
->html()
->sortable()
->collapseOnMobile(),
Column::make('Erstellt am', 'created_at')
->sortable()
->collapseOnMobile(),
Column::make('')
->label(
fn ($row, Column $column) => view('columns.courses.action')->withRow($row)
),
];
}
public function builder(): Builder
{
return Course::query()
->with([
'lecturer',
'tags',
])
->withCount([
'courseEvents' => fn($query) => $query->where('course_events.from', '>', now()),
])
->orderByDesc('course_events_count')
->orderBy('courses.id');
}
public function courseSearch($id)
{
return to_route('school.table.event', [
'#table',
'country' => $this->country,
'course_events' => [
'filters' => [
'course_id' => $id,
],
],
]);
}
}

View File

@@ -1,202 +0,0 @@
<?php
namespace App\Http\Livewire\Tables;
use App\Models\Category;
use App\Models\CourseEvent;
use App\Models\Lecturer;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectFilter;
use Rappasoft\LaravelLivewireTables\Views\Filters\SelectFilter;
use Rappasoft\LaravelLivewireTables\Views\Filters\TextFilter;
class EventTable extends DataTableComponent
{
public string $country;
public bool $viewingModal = false;
public $currentModal;
public string $tableName = 'course_events';
public function configure(): void
{
$this
->setPrimaryKey('id')
->setDefaultSort('from', 'asc')
->setAdditionalSelects([
'course_events.id',
'course_events.created_by',
'course_id',
'venue_id',
])
->setThAttributes(function (Column $column) {
return [
'class' => 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider dark:bg-gray-800 dark:text-gray-400',
'default' => false,
];
})
->setTdAttributes(function (Column $column, $row, $columnIndex, $rowIndex) {
return [
'class' => 'px-6 py-4 text-sm font-medium dark:text-white',
'default' => false,
];
})
->setColumnSelectStatus(false)
->setPerPage(10)
->setConfigurableAreas([
'toolbar-left-end' => [
'columns.course-events.areas.toolbar-left-end', [
'country' => $this->country,
],
],
]);
}
public function filters(): array
{
return [
TextFilter::make('Event by ID', 'byid')
->hiddenFromMenus()
->filter(function (Builder $builder, string $value) {
$builder->whereIn('course_events.id', str($value)->explode(','));
}),
TextFilter::make(__('City'))
->config([
'placeholder' => __('Search City'),
])
->filter(function (Builder $builder, string $value) {
if (str($value)->contains(',')) {
$builder
->whereHas('venue.city',
function ($query) use ($value) {
$query->whereIn('cities.name', str($value)->explode(','));
});
} else {
$builder->whereHas('venue.city',
fn ($query) => $query->where('cities.name', 'ilike', "%$value%"));
}
}),
TextFilter::make(__('Venue'), 'venue')
->config([
'placeholder' => __('Search Venue'),
])
->filter(function (Builder $builder, string $value) {
$builder->whereHas('venue',
fn ($query) => $query->where('venues.name', 'ilike', "%$value%"));
}),
TextFilter::make(__('Course'))
->config([
'placeholder' => __('Search Course'),
])
->filter(function (Builder $builder, string $value) {
$builder->whereHas('course',
fn ($query) => $query->where('courses.name', 'ilike', "%$value%"));
}),
TextFilter::make('Course by ID', 'course_id')
->hiddenFromMenus()
->filter(function (Builder $builder, string $value) {
$builder->whereHas('course',
fn ($query) => $query->where('courses.id', '=', $value));
}),
MultiSelectFilter::make(__('Type'))
->options(
Category::query()
->pluck('name', 'id')
->toArray()
)
->filter(function (Builder $builder, array $values) {
$builder->whereHas('course.categories',
fn ($query) => $query->whereIn('categories.id', $values));
}),
SelectFilter::make(__('Lecturer'))
->options(
Lecturer::query()
->pluck('name', 'id')
->toArray()
)
->filter(function (Builder $builder, string $value) {
$builder->whereHas('course.lecturer',
fn ($query) => $query->where('lecturers.id', $value));
}),
];
}
public function columns(): array
{
return [
Column::make(_('City'), 'venue.city.name')
->sortable()
->collapseOnMobile(),
Column::make(__('Venue'), 'venue.name')
->sortable()
->collapseOnMobile(),
Column::make(__('Lecturer'), 'course.lecturer.name')
->label(
fn ($row, Column $column) => view('columns.events.lecturer')->withRow($row)
)
->sortable()
->collapseOnMobile(),
Column::make(__('Course'), 'course.name')
->sortable(),
Column::make(__('Type'))
->label(
fn ($row, Column $column) => view('columns.events.categories')->withRow($row)
)
->collapseOnMobile(),
Column::make(__('From'), 'from')
->format(
fn ($value, $row, Column $column) => $value->asDateTime()
)
->sortable(),
Column::make(__('To'), 'to')
->format(
fn ($value, $row, Column $column) => $value->asDateTime()
)
->sortable()
->collapseOnMobile(),
/*Column::make("Teilnehmer")
->label(
fn($row, Column $column) => '<strong>'.$row->registrations->count().'</strong>'
)
->html()
->sortable(),*/
Column::make(__('Actions'))
->label(
fn ($row, Column $column) => view('columns.events.action')->withRow($row)
)
->collapseOnMobile(),
];
}
public function builder(): Builder
{
return CourseEvent::query()
->with([
'course.lecturer',
'course.categories',
])
->where('from', '>=', now())
->whereHas('venue.city.country',
fn ($query) => $query->where('countries.code', $this->country));
}
public function viewHistoryModal($modelId): void
{
$this->viewingModal = true;
$this->currentModal = CourseEvent::findOrFail($modelId);
}
public function resetModal(): void
{
$this->reset('viewingModal', 'currentModal');
}
public function customView(): string
{
return 'modals.events.register';
}
}

View File

@@ -1,118 +0,0 @@
<?php
namespace App\Http\Livewire\Tables;
use App\Models\Lecturer;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use Rappasoft\LaravelLivewireTables\Views\Columns\BooleanColumn;
use Rappasoft\LaravelLivewireTables\Views\Columns\ImageColumn;
class LecturerTable extends DataTableComponent
{
public string $country;
public string $tableName = 'lecturers';
public function configure(): void
{
$this->setPrimaryKey('id')
->setAdditionalSelects(['id'])
->setThAttributes(function (Column $column) {
return [
'class' => 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider dark:bg-gray-800 dark:text-gray-400',
'default' => false,
];
})
->setTdAttributes(function (Column $column, $row, $columnIndex, $rowIndex) {
return [
'class' => 'px-6 py-4 text-sm font-medium dark:text-white',
'default' => false,
];
})
->setColumnSelectStatus(false)
->setPerPage(10)
->setConfigurableAreas([
'toolbar-left-end' => [
'columns.lectures.areas.toolbar-left-end', [
'country' => $this->country,
],
],
]);
}
public function columns(): array
{
return [
ImageColumn::make('Bild')
->location(
fn ($row) => $row->getFirstMediaUrl('avatar', 'thumb')
)
->attributes(fn ($row) => [
'class' => 'rounded h-16 w-16',
'alt' => $row->name.' Avatar',
])
->collapseOnMobile(),
Column::make('Name', 'name')
->searchable(fn ($query, $term) => $query->where('name', 'ilike', '%'.$term.'%'))
->sortable(),
BooleanColumn::make('Aktiv', 'active')
->sortable()
->collapseOnMobile(),
Column::make('Kurse')
->label(
fn ($row, Column $column) => $row->courses_count
)
->collapseOnMobile(),
Column::make('Inhalte')
->label(
fn ($row, Column $column) => $row->library_items_count
)
->collapseOnMobile(),
Column::make('')
->label(
fn ($row, Column $column) => view('columns.lectures.action')
->withRow($row)
->withCountry($this->country)
),
];
}
public function builder(): Builder
{
return Lecturer::query()
->withCount([
'courses',
'coursesEvents',
'libraryItems' => fn($query) => $query->where('news', false)
]);
}
public function lecturerSearch($id, $event = true)
{
$lecturer = Lecturer::query()
->find($id);
if ($event) {
return to_route('school.table.event', [
'#table',
'country' => $this->country,
'course_events' => [
'filters' => [
'dozent' => $lecturer->id,
],
],
]);
} else {
return to_route('library.table.libraryItems', [
'#table',
'country' => $this->country,
'filters' => [
'lecturer_id' => $lecturer->id,
],
]);
}
}
}

View File

@@ -1,187 +0,0 @@
<?php
namespace App\Http\Livewire\Tables;
use App\Enums\LibraryItemType;
use App\Models\Library;
use App\Models\LibraryItem;
use App\Models\Tag;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use Rappasoft\LaravelLivewireTables\Views\Filters\MultiSelectFilter;
use Rappasoft\LaravelLivewireTables\Views\Filters\SelectFilter;
use Rappasoft\LaravelLivewireTables\Views\Filters\TextFilter;
use Spatie\LaravelOptions\Options;
class LibraryItemTable extends DataTableComponent
{
public string $currentTab;
public string $tableName = 'library_items';
public function configure(): void
{
$this
->setPrimaryKey('id')
->setAdditionalSelects(['id'])
->setDefaultSort('order_column', 'asc')
->setThAttributes(function (Column $column) {
return [
'class' => 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider dark:bg-gray-800 dark:text-gray-400',
'default' => false,
];
})
->setTdAttributes(function (Column $column, $row, $columnIndex, $rowIndex) {
return [
'class' => 'px-6 py-4 text-sm font-medium dark:text-white',
'default' => false,
];
})
->setColumnSelectStatus(false)
->setPerPage(10);
}
public function filters(): array
{
return [
TextFilter::make(__('By id'), 'id')
->hiddenFromMenus()
->filter(function (Builder $builder, string $value) {
$builder->where('library_items.id', '=', $value);
}),
TextFilter::make(__('By lecturer'), 'lecturer_id')
->hiddenFromMenus()
->filter(function (Builder $builder, string $value) {
$builder->where('library_items.lecturer_id', '=', $value);
}),
MultiSelectFilter::make('Tag')
->options(
Tag::query()
->where('type', 'library_item')
->get()
->pluck('name', 'id')
->toArray()
)
->filter(function (Builder $builder, array $values) {
$builder->whereHas('tags', function (Builder $query) use ($values) {
$query->whereIn('tags.id', $values);
});
}),
SelectFilter::make('Bibliothek')
->options(
Library::query()
->where('is_public', true)
->get()
->prepend(new Library(['name' => '*']))
->pluck('name', 'name')
->toArray(),
)
->filter(function (Builder $builder, string $value) {
if ($value === '*') {
return;
}
if (str($value)->contains(',')) {
$builder
->whereHas('libraries',
function ($query) use ($value) {
$query->whereIn('libraries.name', str($value)->explode(','));
});
} else {
$builder->whereHas('libraries',
fn ($query) => $query->where('libraries.name', 'ilike', "%$value%"));
}
}),
SelectFilter::make('Art')
->options(
collect(
Options::forEnum(LibraryItemType::class)
->toArray()
)
->mapWithKeys(fn ($value, $key) => [$value['value'] => $value['label']])
->prepend('*', '')
->toArray()
)
->filter(function (Builder $builder, string $value) {
if ($value === '*') {
return;
}
$builder->where('library_items.type', $value);
}),
];
}
public function columns(): array
{
return [
Column::make(__('Image'))
->label(
fn ($row, Column $column) => view('columns.library_items.image')->withRow($row)
)
->collapseOnMobile(),
Column::make(__('Creator'), 'lecturer.name')
->label(
fn ($row, Column $column) => view('columns.courses.lecturer')->withRow($row)
)
->sortable()
->collapseOnMobile(),
Column::make('Name', 'name')
->sortable(),
Column::make('Art', 'type')
->format(
function ($value, $row, Column $column) {
return '<span class="whitespace-nowrap inline-flex items-center rounded-full bg-amber-400 px-2.5 py-0.5 text-base font-medium text-gray-900"><i class="mr-2 fa fa-thin fa-'
.LibraryItemType::icons()[$value]
.'"></i>'
.LibraryItemType::labels()[$value]
.'</span>';
})
->html()
->sortable()
->collapseOnMobile(),
Column::make('Tags')
->label(
fn ($row, Column $column) => view('columns.library_items.tags')->withRow($row)
)
->collapseOnMobile(),
Column::make('')
->label(
fn ($row, Column $column) => view('columns.library_items.action')->withRow($row)
),
];
}
public function builder(): Builder
{
$shouldBePublic = request()
?->route()
?->getName() !== 'library.table.lecturer';
if ($this->currentTab !== '*') {
$parentLibrary = Library::query()
->where('name', $this->currentTab)
->first();
}
return LibraryItem::query()
->with([
'lecturer',
'tags',
])
->whereHas('libraries', fn ($query) => $query->where('libraries.is_public', $shouldBePublic))
->when($this->currentTab !== '*', fn ($query) => $query
->whereHas('libraries',
fn ($query) => $query
->where('libraries.name', $this->currentTab)
)
->orWhereHas('libraries',
fn ($query) => $query
->where('libraries.parent_id', $parentLibrary->id)
)
)
->withCount([
'lecturer',
])
->currentStatus('published');
}
}

View File

@@ -1,117 +0,0 @@
<?php
namespace App\Http\Livewire\Tables;
use App\Models\MeetupEvent;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use Rappasoft\LaravelLivewireTables\Views\Filters\TextFilter;
class MeetupEventTable extends DataTableComponent
{
public string $country;
public string $tableName = 'meetup_events';
public function configure(): void
{
$this->setPrimaryKey('id')
->setAdditionalSelects(['meetup_events.id', 'meetup_events.meetup_id', 'attendees', 'might_attendees'])
->setDefaultSort('start', 'asc')
->setThAttributes(function (Column $column) {
return [
'class' => 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider dark:bg-gray-800 dark:text-gray-400',
'default' => false,
];
})
->setTdAttributes(function (Column $column, $row, $columnIndex, $rowIndex) {
return [
'class' => 'px-6 py-4 text-sm font-medium dark:text-white',
'default' => false,
];
})
->setColumnSelectStatus(false)
->setPerPage(10)
->setConfigurableAreas([
'toolbar-left-end' => [
'columns.meetup_events.areas.toolbar-left-end', [
'country' => $this->country,
],
],
]);
}
public function filters(): array
{
return [
TextFilter::make('Meetup-Event by ID', 'bymeetupid')
->hiddenFromMenus()
->filter(function (Builder $builder, string $value) {
$builder->whereIn('meetup_events.meetup_id', str($value)->explode(','));
}),
TextFilter::make('Meetup-Event by ID', 'byid')
->hiddenFromMenus()
->filter(function (Builder $builder, string $value) {
$builder->whereIn('meetup_events.id', str($value)->explode(','));
}),
];
}
public function columns(): array
{
$columns = [
Column::make(__('Meetup'), 'meetup.name')
->format(
fn ($value, $row, Column $column) => view('columns.meetup_events.name')
->withRow($row)
->withCountry($this->country)
)
->searchable(fn ($builder, $term) => $builder->where('meetups.name', 'ilike', '%'.$term.'%'))
->sortable(),
Column::make(__('Location'), 'location')
->searchable(fn ($builder, $term) => $builder->where('location', 'ilike', '%'.$term.'%'))
->sortable()
->collapseOnMobile(),
Column::make(__('Start'), 'start')
->format(
fn ($value, $row, Column $column) => $value->asDateTime()
)
->sortable()
->collapseOnMobile(),
Column::make(__('Confirmations'))
->label(
fn ($row, Column $column) => view('columns.meetup_events.confirmations')
->withRow($row)
)
->collapseOnMobile(),
Column::make(__('Link'))
->label(
fn ($row, Column $column) => view('columns.meetup_events.link')
->withRow($row)
)
->collapseOnMobile(),
];
$adminColumns = auth()->check() ? [
Column::make(__('Actions'))
->label(
fn ($row, Column $column) => view('columns.meetup_events.manage')
->withRow($row)
)
->collapseOnMobile(),
] : [];
return array_merge($columns, $adminColumns);
}
public function builder(): Builder
{
return MeetupEvent::query()
->where('meetup_events.start', '>=', now()->subDay())
->whereHas('meetup.city.country', fn ($query) => $query->where('code', $this->country))
->with([
'meetup.city.country',
]);
}
}

View File

@@ -1,54 +0,0 @@
<?php
namespace App\Http\Livewire\Tables;
use App\Models\Meetup;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
class MeetupForBtcMapTable extends DataTableComponent
{
public function configure(): void
{
$this
->setPrimaryKey('id')
->setAdditionalSelects([
'osm_relation',
'simplified_geojson',
'population',
'population_date',
'city_id',
])
->setPerPageAccepted([
100000,
])
->setPerPage(100000);
}
public function columns(): array
{
return [
Column::make('Id', 'id')
->sortable(),
Column::make('Name', 'name')
->sortable(),
Column::make('City', 'city.name')
->sortable(),
Column::make('Country', 'city.country.name')
->sortable(),
Column::make('Actions')
->label(fn($row, Column $column) => view('columns.meetups.osm-actions', ['row' => $row])),
];
}
public function builder(): Builder
{
return Meetup::query()
->with([
'city.country',
])
->where('community', '=', 'einundzwanzig')
->orderBy('cities.population');
}
}

View File

@@ -1,112 +0,0 @@
<?php
namespace App\Http\Livewire\Tables;
use App\Models\Meetup;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use Rappasoft\LaravelLivewireTables\Views\Filters\TextFilter;
class MeetupTable extends DataTableComponent
{
public ?string $country = null;
public string $tableName = 'meetups';
public function configure(): void
{
$this->setPrimaryKey('id')
->setAdditionalSelects(['meetups.id', 'meetups.slug', 'meetups.created_by'])
->setThAttributes(function (Column $column) {
return [
'class' => 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider dark:bg-gray-800 dark:text-gray-400',
'default' => false,
];
})
->setTdAttributes(function (Column $column, $row, $columnIndex, $rowIndex) {
return [
'class' => 'px-6 py-4 text-sm font-medium dark:text-white',
'default' => false,
];
})
->setColumnSelectStatus(false)
->setPerPage(10)
->setConfigurableAreas([
'toolbar-left-end' => [
'columns.meetups.areas.toolbar-left-end', [
'country' => $this->country,
],
],
]);
}
public function filters(): array
{
return [
TextFilter::make('Meetup by ID', 'byid')
->hiddenFromMenus()
->filter(function (Builder $builder, string $value) {
$builder->whereIn('meetups.id', str($value)->explode(','));
}),
];
}
public function columns(): array
{
return [
Column::make(__('Name'), 'name')
->format(
fn ($value, $row, Column $column) => view('columns.meetups.name')
->withRow($row)
)
->searchable(fn ($builder, $term) => $builder->where('meetups.name', 'ilike', '%'.$term.'%')),
Column::make(__('Plebs'))
->label(fn ($row, Column $column) => $row->users_count)
->collapseOnMobile(),
Column::make(__('Links'))
->label(
fn ($row, Column $column) => view('columns.meetups.action')
->withRow($row)
->withIcs(route('meetup.ics',
['country' => $this->country ?? $row->city->country->code, 'meetup' => $row->id]))
->withCountry($this->country)
)
->collapseOnMobile(),
];
}
public function builder(): Builder
{
return Meetup::query()
->with([
'users',
'city.country',
'meetupEvents',
])
->when($this->country,
fn ($query, $country) => $query->whereRelation('city.country', 'code', $this->country))
->withCount([
'users',
'meetupEvents' => fn ($query) => $query->where('start', '>=',
now()),
])
->when(! $this->country, fn ($query) => $query->orderByDesc('users_count')
->orderBy('meetups.id'))
->when($this->country, fn ($query) => $query->orderByDesc('meetup_events_count')
->orderBy('meetups.id'));
}
public function meetupEventSearch($id)
{
$meetup = Meetup::with(['city.country'])
->find($id);
return to_route('meetup.table.meetupEvent', [
'country' => $this->country ?? $meetup->city->country->code,
'meetup_events' => [
'filters' => ['bymeetupid' => $id],
],
]);
}
}

View File

@@ -1,70 +0,0 @@
<?php
namespace App\Http\Livewire\Tables;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use App\Models\ProjectProposal;
class ProjectProposalTable extends DataTableComponent
{
public ?string $country = null;
public string $tableName = 'project_proposals';
public function configure(): void
{
$this->setPrimaryKey('id')
->setAdditionalSelects(['project_proposals.id', 'project_proposals.created_by', 'project_proposals.slug', 'project_proposals.user_id'])
->setThAttributes(function (Column $column) {
return [
'class' => 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider dark:bg-gray-800 dark:text-gray-400',
'default' => false,
];
})
->setTdAttributes(function (Column $column, $row, $columnIndex, $rowIndex) {
return [
'class' => 'px-6 py-4 text-sm font-medium dark:text-white',
'default' => false,
];
})
->setColumnSelectStatus(false)
->setPerPage(10)
->setConfigurableAreas([
'toolbar-left-end' => [
'columns.project_proposals.areas.toolbar-left-end', [
'country' => $this->country,
],
],
]);
}
public function columns(): array
{
return [
Column::make("Id", "id")
->sortable(),
Column::make(__('From'))
->label(
fn ($row, Column $column) => view('columns.project_proposals.author')->withRow($row)
),
Column::make("Name", "name")
->sortable(),
Column::make(__('Intended support in sats'), "support_in_sats")
->format(
fn ($value, $row, Column $column) => number_format($value, 0, ',', '.')
)
->sortable(),
Column::make('')
->label(
fn ($row, Column $column) => view('columns.project_proposals.action')->withRow($row)->withCountry($this->country)
),
];
}
public function builder(): Builder
{
return ProjectProposal::query()->with(['user']);
}
}

View File

@@ -1,102 +0,0 @@
<?php
namespace App\Http\Livewire\Tables;
use App\Models\Venue;
use Illuminate\Database\Eloquent\Builder;
use Rappasoft\LaravelLivewireTables\DataTableComponent;
use Rappasoft\LaravelLivewireTables\Views\Column;
use Rappasoft\LaravelLivewireTables\Views\Columns\ImageColumn;
class VenueTable extends DataTableComponent
{
public string $country;
public bool $manage = false;
public string $tableName = 'venues';
public function configure(): void
{
$this->setPrimaryKey('id')
->setAdditionalSelects(['venues.id', 'venues.created_by'])
->setThAttributes(function (Column $column) {
return [
'class' => 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider dark:bg-gray-800 dark:text-gray-400',
'default' => false,
];
})
->setTdAttributes(function (Column $column, $row, $columnIndex, $rowIndex) {
return [
'class' => 'px-6 py-4 text-sm font-medium dark:text-white',
'default' => false,
];
})
->setColumnSelectStatus(false)
->setPerPage(10)
->setConfigurableAreas([
'toolbar-left-end' => [
'columns.venues.areas.toolbar-left-end', [
'country' => $this->country,
],
],
]);
}
public function columns(): array
{
return [
ImageColumn::make('Bild')
->location(
fn ($row) => $row->getFirstMediaUrl('images', 'thumb')
)
->attributes(fn ($row) => [
'class' => 'rounded h-16 w-16',
'alt' => $row->name.' Avatar',
])
->collapseOnMobile(),
Column::make('Name', 'name')
->searchable(fn ($query, $term) => $query->where('name', 'ilike', '%'.$term.'%'))
->sortable(),
Column::make('Street', 'street')
->sortable()
->collapseOnMobile(),
Column::make('Termine')
->label(
fn ($row, Column $column) => $row->course_events_count
)
->collapseOnMobile(),
Column::make('')
->label(
fn ($row, Column $column) => view('columns.venues.action')->withRow($row)->withManage($this->manage)
),
];
}
public function builder(): Builder
{
return Venue::query()
->withCount([
'courseEvents',
])
->whereHas('city.country', fn ($query) => $query->where('code', $this->country))
->orderByDesc('course_events_count')
->orderBy('venues.id');
}
public function venueSearch($id)
{
$venue = Venue::query()
->find($id);
return to_route('school.table.event', [
'#table',
'country' => $this->country,
'course_events' => [
'filters' => [
'venue' => $venue->name,
],
],
]);
}
}

View File

@@ -1,89 +0,0 @@
<?php
namespace App\Http\Livewire\Venue\Form;
use App\Models\Venue;
use Illuminate\Validation\Rule;
use Livewire\Component;
use Livewire\WithFileUploads;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use WireUi\Traits\Actions;
class VenueForm extends Component
{
use WithFileUploads;
use Actions;
public string $country;
public ?Venue $venue = null;
public $images;
public ?string $fromUrl = '';
protected $queryString = ['fromUrl' => ['except' => '']];
protected $listeners = ['refresh' => '$refresh'];
public function rules()
{
return [
'images.*' => [Rule::requiredIf(!$this->venue->id), 'nullable', 'mimes:jpeg,png,jpg,gif', 'max:10240'],
'venue.city_id' => 'required',
'venue.name' => [
'required',
Rule::unique('venues', 'name')
->ignore($this->venue),
],
'venue.street' => 'required',
];
}
public function mount()
{
if (!$this->venue) {
$this->venue = new Venue();
} elseif (!auth()
->user()
->can('update', $this->venue)) {
abort(403);
}
if (!$this->fromUrl) {
$this->fromUrl = url()->previous();
}
}
public function deleteMedia($id)
{
Media::query()
->find($id)
->delete();
$this->notification()
->success(__('Image deleted!'));
$this->emit('refresh');
}
public function submit()
{
$this->validate();
$this->venue->save();
if ($this->images && count($this->images) > 0) {
foreach ($this->images as $item) {
$this->venue->addMedia($item)
->usingFileName(md5($item->getClientOriginalName()).'.'.$item->getClientOriginalExtension())
->toMediaCollection('images');
}
}
return redirect($this->fromUrl);
}
public function render()
{
return view('livewire.venue.form.venue-form');
}
}

View File

@@ -1,71 +0,0 @@
<?php
namespace App\Http\Livewire\Wallet;
use App\Models\LoginKey;
use eza\lnurl;
use Livewire\Component;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
class LightningWallet extends Component
{
public ?string $k1 = null;
public ?string $url = null;
public ?string $lnurl = null;
public ?string $qrCode = null;
public bool $confirmed = false;
public function rules()
{
return [
'k1' => 'required',
'url' => 'required',
'lnurl' => 'required',
'qrCode' => 'required',
];
}
public function mount()
{
$this->k1 = bin2hex(str()->random(32));
if (app()->environment('local')) {
$this->url = 'https://einundzwanzig.eu-1.sharedwithexpose.com/api/lnurl-auth-callback?tag=login&k1='.$this->k1.'&action=login';
} else {
$this->url = url('/api/lnurl-auth-callback?tag=login&k1='.$this->k1.'&action=login');
}
$this->lnurl = lnurl\encodeUrl($this->url);
$this->qrCode = base64_encode(QrCode::format('png')
->size(300)
->merge('/public/android-chrome-192x192.png', .3)
->errorCorrection('H')
->generate($this->lnurl));
}
public function confirm()
{
$user = auth()->user();
$user->change = $this->k1;
$user->change_time = now();
$user->save();
$this->confirmed = true;
}
public function checkAuth()
{
$loginKey = LoginKey::query()
->where('k1', $this->k1)
->whereDate('created_at', '>=', now()->subMinutes(5))
->first();
// you should also restrict this 👆🏻 by time, and find only the $k1 that were created in the last 5 minutes
if ($loginKey) {
return to_route('welcome');
}
}
public function render()
{
return view('livewire.wallet.lightning-wallet');
}
}

View File

@@ -1,169 +0,0 @@
<div>
<!-- Generate API Token -->
<x-jet-form-section submit="createApiToken">
<x-slot name="title">
{{ __('Create API Token') }}
</x-slot>
<x-slot name="description">
{{ __('API tokens allow third-party services to authenticate with our application on your behalf.') }}
</x-slot>
<x-slot name="form">
<!-- Token Name -->
<div class="col-span-6 sm:col-span-4">
<x-jet-label for="name" value="{{ __('Token Name') }}" />
<x-jet-input id="name" type="text" class="mt-1 block w-full" wire:model.defer="createApiTokenForm.name" autofocus />
<x-jet-input-error for="name" class="mt-2" />
</div>
<!-- Token Permissions -->
@if (Laravel\Jetstream\Jetstream::hasPermissions())
<div class="col-span-6">
<x-jet-label for="permissions" value="{{ __('Permissions') }}" />
<div class="mt-2 grid grid-cols-1 md:grid-cols-2 gap-4">
@foreach (Laravel\Jetstream\Jetstream::$permissions as $permission)
<label class="flex items-center">
<x-jet-checkbox wire:model.defer="createApiTokenForm.permissions" :value="$permission"/>
<span class="ml-2 text-sm text-gray-600">{{ $permission }}</span>
</label>
@endforeach
</div>
</div>
@endif
</x-slot>
<x-slot name="actions">
<x-jet-action-message class="mr-3" on="created">
{{ __('Created.') }}
</x-jet-action-message>
<x-jet-button>
{{ __('Create') }}
</x-jet-button>
</x-slot>
</x-jet-form-section>
@if ($this->user->tokens->isNotEmpty())
<x-jet-section-border />
<!-- Manage API Tokens -->
<div class="mt-10 sm:mt-0">
<x-jet-action-section>
<x-slot name="title">
{{ __('Manage API Tokens') }}
</x-slot>
<x-slot name="description">
{{ __('You may delete any of your existing tokens if they are no longer needed.') }}
</x-slot>
<!-- API Token List -->
<x-slot name="content">
<div class="space-y-6">
@foreach ($this->user->tokens->sortBy('name') as $token)
<div class="flex items-center justify-between">
<div>
{{ $token->name }}
</div>
<div class="flex items-center">
@if ($token->last_used_at)
<div class="text-sm text-gray-400">
{{ __('Last used') }} {{ $token->last_used_at->diffForHumans() }}
</div>
@endif
@if (Laravel\Jetstream\Jetstream::hasPermissions())
<button class="cursor-pointer ml-6 text-sm text-gray-400 underline" wire:click="manageApiTokenPermissions({{ $token->id }})">
{{ __('Permissions') }}
</button>
@endif
<button class="cursor-pointer ml-6 text-sm text-red-500" wire:click="confirmApiTokenDeletion({{ $token->id }})">
{{ __('Delete') }}
</button>
</div>
</div>
@endforeach
</div>
</x-slot>
</x-jet-action-section>
</div>
@endif
<!-- Token Value Modal -->
<x-jet-dialog-modal wire:model="displayingToken">
<x-slot name="title">
{{ __('API Token') }}
</x-slot>
<x-slot name="content">
<div>
{{ __('Please copy your new API token. For your security, it won\'t be shown again.') }}
</div>
<x-jet-input x-ref="plaintextToken" type="text" readonly :value="$plainTextToken"
class="mt-4 bg-gray-100 px-4 py-2 rounded font-mono text-sm text-gray-500 w-full"
autofocus autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
@showing-token-modal.window="setTimeout(() => $refs.plaintextToken.select(), 250)"
/>
</x-slot>
<x-slot name="footer">
<x-jet-secondary-button wire:click="$set('displayingToken', false)" wire:loading.attr="disabled">
{{ __('Close') }}
</x-jet-secondary-button>
</x-slot>
</x-jet-dialog-modal>
<!-- API Token Permissions Modal -->
<x-jet-dialog-modal wire:model="managingApiTokenPermissions">
<x-slot name="title">
{{ __('API Token Permissions') }}
</x-slot>
<x-slot name="content">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
@foreach (Laravel\Jetstream\Jetstream::$permissions as $permission)
<label class="flex items-center">
<x-jet-checkbox wire:model.defer="updateApiTokenForm.permissions" :value="$permission"/>
<span class="ml-2 text-sm text-gray-600">{{ $permission }}</span>
</label>
@endforeach
</div>
</x-slot>
<x-slot name="footer">
<x-jet-secondary-button wire:click="$set('managingApiTokenPermissions', false)" wire:loading.attr="disabled">
{{ __('Cancel') }}
</x-jet-secondary-button>
<x-jet-button class="ml-3" wire:click="updateApiToken" wire:loading.attr="disabled">
{{ __('Save') }}
</x-jet-button>
</x-slot>
</x-jet-dialog-modal>
<!-- Delete Token Confirmation Modal -->
<x-jet-confirmation-modal wire:model="confirmingApiTokenDeletion">
<x-slot name="title">
{{ __('Delete API Token') }}
</x-slot>
<x-slot name="content">
{{ __('Are you sure you would like to delete this API token?') }}
</x-slot>
<x-slot name="footer">
<x-jet-secondary-button wire:click="$toggle('confirmingApiTokenDeletion')" wire:loading.attr="disabled">
{{ __('Cancel') }}
</x-jet-secondary-button>
<x-jet-danger-button class="ml-3" wire:click="deleteApiToken" wire:loading.attr="disabled">
{{ __('Delete') }}
</x-jet-danger-button>
</x-slot>
</x-jet-confirmation-modal>
</div>

View File

@@ -1,13 +0,0 @@
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
{{ __('API Tokens') }}
</h2>
</x-slot>
<div>
<div class="max-w-7xl mx-auto py-10 sm:px-6 lg:px-8">
@livewire('api.api-token-manager')
</div>
</div>
</x-app-layout>

View File

@@ -1,28 +0,0 @@
<x-guest-layout>
<x-jet-authentication-card>
<x-slot name="logo">
<x-jet-authentication-card-logo />
</x-slot>
<div class="mb-4 text-sm text-gray-600">
{{ __('This is a secure area of the application. Please confirm your password before continuing.') }}
</div>
<x-jet-validation-errors class="mb-4" />
<form method="POST" action="{{ route('password.confirm') }}">
@csrf
<div>
<x-jet-label for="password" value="{{ __('Password') }}" />
<x-jet-input id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="current-password" autofocus />
</div>
<div class="flex justify-end mt-4">
<x-jet-button class="ml-4">
{{ __('Confirm') }}
</x-jet-button>
</div>
</form>
</x-jet-authentication-card>
</x-guest-layout>

View File

@@ -1,34 +0,0 @@
<x-guest-layout>
<x-jet-authentication-card>
<x-slot name="logo">
<x-jet-authentication-card-logo />
</x-slot>
<div class="mb-4 text-sm text-gray-600">
{{ __('Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.') }}
</div>
@if (session('status'))
<div class="mb-4 font-medium text-sm text-green-600">
{{ session('status') }}
</div>
@endif
<x-jet-validation-errors class="mb-4" />
<form method="POST" action="{{ route('password.email') }}">
@csrf
<div class="block">
<x-jet-label for="email" value="{{ __('Email') }}" />
<x-jet-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autofocus />
</div>
<div class="flex items-center justify-end mt-4">
<x-jet-button>
{{ __('Email Password Reset Link') }}
</x-jet-button>
</div>
</form>
</x-jet-authentication-card>
</x-guest-layout>

View File

@@ -1,72 +0,0 @@
<x-guest-layout>
<x-jet-authentication-card>
<x-slot name="logo">
<x-jet-authentication-card-logo/>
</x-slot>
<x-jet-validation-errors class="mb-4"/>
@if (session('status'))
<div class="mb-4 font-medium text-sm text-green-600">
{{ session('status') }}
</div>
@endif
<form method="POST" action="{{ route('login') }}">
<div class="flex items-center justify-end mb-4">
<x-button icon="arrow-left" secondary class="ml-4" href="/">
{{ __('Back to the website') }}
</x-button>
</div>
@csrf
<div>
<x-jet-label for="email" value="{{ __('Email') }}"/>
<x-jet-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')"
required autofocus/>
@if(app()->environment())
<pre>admin@einundzwanzig.space</pre>
@endif
</div>
<div class="mt-4">
<x-jet-label for="password" value="{{ __('Password') }}"/>
<x-jet-input id="password" class="block mt-1 w-full" type="password" name="password" required
autocomplete="current-password"/>
@if(app()->environment())
<pre>1234</pre>
@endif
</div>
<div class="block mt-4">
<label for="remember_me" class="flex items-center">
<x-jet-checkbox id="remember_me" name="remember"/>
<span class="ml-2 text-sm text-gray-600">{{ __('Remember me') }}</span>
</label>
</div>
@if(app()->environment('local'))
<div class="flex items-center justify-end mt-4">
@if (Route::has('password.request'))
<a class="underline text-sm text-gray-600 hover:text-gray-900"
href="{{ route('password.request') }}">
{{ __('Forgot your password?') }}
</a>
@endif
<x-jet-button class="ml-4">
{{ __('Log in') }}
</x-jet-button>
</div>
@endif
<div class="flex items-center justify-left mt-4">
<x-button href="{{ route('auth.login') }}" primary icon="lightning-bolt">LNURL-Auth</x-button>
</div>
</form>
</x-jet-authentication-card>
</x-guest-layout>

View File

@@ -1,86 +0,0 @@
<x-guest-layout>
<x-jet-authentication-card>
<x-slot name="logo">
<x-jet-authentication-card-logo/>
</x-slot>
<x-jet-validation-errors class="mb-4"/>
<form method="POST" action="{{ route('register') }}">
<div class="flex items-center justify-end mb-4">
<x-button icon="arrow-left" secondary class="ml-4" href="/">
{{ __('Back to the website') }}
</x-button>
</div>
@csrf
<div>
<x-jet-label for="name" value="{{ __('Name') }}"/>
<x-jet-input id="name" class="block mt-1 w-full" type="text" name="name" :value="old('name')" required
autofocus autocomplete="name"/>
</div>
<div class="mt-4">
<x-jet-label for="email" value="{{ __('Email') }}"/>
<x-jet-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')"
required/>
</div>
<div class="mt-4">
<x-jet-label for="password" value="{{ __('Password') }}"/>
<x-jet-input id="password" class="block mt-1 w-full" type="password" name="password" required
autocomplete="new-password"/>
</div>
<div class="mt-4">
<x-jet-label for="password_confirmation" value="{{ __('Confirm Password') }}"/>
<x-jet-input id="password_confirmation" class="block mt-1 w-full" type="password"
name="password_confirmation" required autocomplete="new-password"/>
</div>
<div class="mt-4">
<x-jet-label for="is_lecturer">
<div class="flex items-center">
<x-jet-checkbox name="is_lecturer" id="is_lecturer" required/>
<div class="ml-2">
{{ __('I want to submit new courses on this platform') }}
</div>
</div>
</x-jet-label>
</div>
@if (Laravel\Jetstream\Jetstream::hasTermsAndPrivacyPolicyFeature())
<div class="mt-4">
<x-jet-label for="terms">
<div class="flex items-center">
<x-jet-checkbox name="terms" id="terms" required/>
<div class="ml-2">
{!! __('I agree to the :terms_of_service and :privacy_policy', [
'terms_of_service' => '<a target="_blank" href="'.route('terms.show').'" class="underline text-sm text-gray-600 hover:text-gray-900">'.__('Terms of Service').'</a>',
'privacy_policy' => '<a target="_blank" href="'.route('policy.show').'" class="underline text-sm text-gray-600 hover:text-gray-900">'.__('Privacy Policy').'</a>',
]) !!}
</div>
</div>
</x-jet-label>
</div>
@endif
{{--<div class="flex items-center justify-end mt-4">
<a class="underline text-sm text-gray-600 hover:text-gray-900" href="{{ route('login') }}">
{{ __('Already registered?') }}
</a>
<x-jet-button class="ml-4">
{{ __('Register') }}
</x-jet-button>
</div>--}}
<div class="flex items-center justify-left mt-4">
<x-button href="{{ route('auth.login') }}" primary icon="lightning-bolt">Login</x-button>
</div>
</form>
</x-jet-authentication-card>
</x-guest-layout>

View File

@@ -1,36 +0,0 @@
<x-guest-layout>
<x-jet-authentication-card>
<x-slot name="logo">
<x-jet-authentication-card-logo />
</x-slot>
<x-jet-validation-errors class="mb-4" />
<form method="POST" action="{{ route('password.update') }}">
@csrf
<input type="hidden" name="token" value="{{ $request->route('token') }}">
<div class="block">
<x-jet-label for="email" value="{{ __('Email') }}" />
<x-jet-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email', $request->email)" required autofocus />
</div>
<div class="mt-4">
<x-jet-label for="password" value="{{ __('Password') }}" />
<x-jet-input id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="new-password" />
</div>
<div class="mt-4">
<x-jet-label for="password_confirmation" value="{{ __('Confirm Password') }}" />
<x-jet-input id="password_confirmation" class="block mt-1 w-full" type="password" name="password_confirmation" required autocomplete="new-password" />
</div>
<div class="flex items-center justify-end mt-4">
<x-jet-button>
{{ __('Reset Password') }}
</x-jet-button>
</div>
</form>
</x-jet-authentication-card>
</x-guest-layout>

View File

@@ -1,57 +0,0 @@
<x-guest-layout>
<x-jet-authentication-card>
<x-slot name="logo">
<x-jet-authentication-card-logo />
</x-slot>
<div x-data="{ recovery: false }">
<div class="mb-4 text-sm text-gray-600" x-show="! recovery">
{{ __('Please confirm access to your account by entering the authentication code provided by your authenticator application.') }}
</div>
<div class="mb-4 text-sm text-gray-600" x-show="recovery">
{{ __('Please confirm access to your account by entering one of your emergency recovery codes.') }}
</div>
<x-jet-validation-errors class="mb-4" />
<form method="POST" action="{{ route('two-factor.login') }}">
@csrf
<div class="mt-4" x-show="! recovery">
<x-jet-label for="code" value="{{ __('Code') }}" />
<x-jet-input id="code" class="block mt-1 w-full" type="text" inputmode="numeric" name="code" autofocus x-ref="code" autocomplete="one-time-code" />
</div>
<div class="mt-4" x-show="recovery">
<x-jet-label for="recovery_code" value="{{ __('Recovery Code') }}" />
<x-jet-input id="recovery_code" class="block mt-1 w-full" type="text" name="recovery_code" x-ref="recovery_code" autocomplete="one-time-code" />
</div>
<div class="flex items-center justify-end mt-4">
<button type="button" class="text-sm text-gray-600 hover:text-gray-900 underline cursor-pointer"
x-show="! recovery"
x-on:click="
recovery = true;
$nextTick(() => { $refs.recovery_code.focus() })
">
{{ __('Use a recovery code') }}
</button>
<button type="button" class="text-sm text-gray-600 hover:text-gray-900 underline cursor-pointer"
x-show="recovery"
x-on:click="
recovery = false;
$nextTick(() => { $refs.code.focus() })
">
{{ __('Use an authentication code') }}
</button>
<x-jet-button class="ml-4">
{{ __('Log in') }}
</x-jet-button>
</div>
</form>
</div>
</x-jet-authentication-card>
</x-guest-layout>

View File

@@ -1,45 +0,0 @@
<x-guest-layout>
<x-jet-authentication-card>
<x-slot name="logo">
<x-jet-authentication-card-logo />
</x-slot>
<div class="mb-4 text-sm text-gray-600">
{{ __('Before continuing, could you verify your email address by clicking on the link we just emailed to you? If you didn\'t receive the email, we will gladly send you another.') }}
</div>
@if (session('status') == 'verification-link-sent')
<div class="mb-4 font-medium text-sm text-green-600">
{{ __('A new verification link has been sent to the email address you provided in your profile settings.') }}
</div>
@endif
<div class="mt-4 flex items-center justify-between">
<form method="POST" action="{{ route('verification.send') }}">
@csrf
<div>
<x-jet-button type="submit">
{{ __('Resend Verification Email') }}
</x-jet-button>
</div>
</form>
<div>
<a
href="{{ route('profile.show') }}"
class="underline text-sm text-gray-600 hover:text-gray-900"
>
{{ __('Edit Profile') }}</a>
<form method="POST" action="{{ route('logout') }}" class="inline">
@csrf
<button type="submit" class="underline text-sm text-gray-600 hover:text-gray-900 ml-2">
{{ __('Log Out') }}
</button>
</form>
</div>
</div>
</x-jet-authentication-card>
</x-guest-layout>

View File

@@ -1,6 +0,0 @@
<div class="w-full mb-4 md:w-auto md:mb-0">
<x-button :href="route('bitcoinEvent.form', ['country' => $country, 'bitcoinEvent' => null])">
<i class="fa fa-thin fa-plus"></i>
{{ __('Register event') }}
</x-button>
</div>

View File

@@ -1,7 +0,0 @@
<div class="flex flex-col space-y-1 justify-center items-center">
<img class="h-8" src="{{ asset('vendor/blade-country-flags/1x1-'.$row->venue->city->country->code.'.svg') }}"
alt="{{ $row->venue->city->country->code }}">
<div>
{{ $row->venue->city->country->code }}
</div>
</div>

View File

@@ -1,13 +0,0 @@
<div class="flex flex-col space-y-1">
<a href="{{ $row->link }}" target="_blank">
<x-badge class="whitespace-nowrap">{{ __('Link') }}</x-badge>
</a>
<div>
@can('update', $row)
<x-button primary xs :href="route('bitcoinEvent.form', ['bitcoinEvent' => $row])">
<i class="fa-thin fa-edit"></i>
{{ __('Edit') }}
</x-button>
@endif
</div>
</div>

View File

@@ -1,6 +0,0 @@
<div class="flex items-center space-x-2">
<img class="h-12" src="{{ $row->getFirstMediaUrl('logo', 'thumb') }}" alt="{{ $row->title }}">
<div>
{{ $row->title }}
</div>
</div>

View File

@@ -1,31 +0,0 @@
<div class="flex flex-col space-y-1" wire:key="bookcase_action_{{ $row->id }}">
@auth
<div>
@if($row->orange_pills_count > 0)
<img class="aspect-auto max-h-12" src="{{ asset('img/social_credit_plus.webp') }}" alt="">
@endif
</div>
<div>
@if($row->orange_pills_count < 1)
<img class="aspect-auto max-h-12" src="{{ asset('img/social_credit_minus.webp') }}" alt="">
@endif
</div>
<div class="flex items-center space-x-1">
<x-button xs
:href="route('bookCases.form', ['bookCase' => $row->id, 'country' => $country])"
class="whitespace-nowrap" primary class="text-21gray whitespace-nowrap"
>
{{ __('💊 Orange Pill Now') }}
</x-button>
<x-button xs class="whitespace-nowrap"
:href="route('bookCases.comment.bookcase', ['bookCase' => $row->id, 'country' => $country])">{{ __('Details') }}</x-button>
</div>
@else
<div>
<x-badge class="whitespace-nowrap" amber>
<i class="fa fa-thin fa-shelves-empty mr-2"></i>
{{ __('no bitcoin books yet') }}
</x-badge>
</div>
@endauth
</div>

View File

@@ -1,40 +0,0 @@
<div class="flex flex-col space-y-1">
@if($type === 'school' && !$manage)
<div>
<div>
@if($row->course_events_count > 0)
<x-button xs amber wire:click="proximitySearch({{ $row->id }})" class="text-21gray">
<i class="fa fa-thin fa-person-chalkboard mr-2"></i>
{{ __('Perimeter search course date :name (100km)', ['name' => $row->name]) }}
</x-button>
@endif
</div>
<div>
@if($row->course_events_count < 1)
<x-button xs outlined wire:click="proximitySearch({{ $row->id }})" class="text-21gray">
<i class="fa fa-thin fa-person-chalkboard mr-2"></i>
{{ __('Perimeter search course date :name (100km)', ['name' => $row->name]) }}
</x-button>
@endif
</div>
</div>
@endif
<div>
@if($type === 'bookCase' && !$manage)
<div>
<x-button xs amber wire:click="proximitySearchForBookCases({{ $row->id }})" class="text-21gray">
<i class="fa fa-thin fa-book mr-2"></i>
{{ __('Perimeter search bookcase :name (25km)', ['name' => $row->name]) }}
</x-button>
</div>
@endif
</div>
<div>
@can('update', $row)
<x-button xs :href="route('city.form', ['city' => $row])">
<i class="fa fa-thin fa-edit"></i>
{{ __('Edit') }}
</x-button>
@endcan
</div>
</div>

View File

@@ -1,6 +0,0 @@
<div class="w-full mb-4 md:w-auto md:mb-0">
<x-button :href="route('city.form')">
<i class="fa fa-thin fa-plus"></i>
{{ __('New City') }}
</x-button>
</div>

View File

@@ -1,6 +0,0 @@
<div class="w-full mb-4 md:w-auto md:mb-0">
<x-button xs :href="route('course.form.courseEvent')">
<i class="fa fa-thin fa-plus"></i>
{{ __('Register course date') }}
</x-button>
</div>

View File

@@ -1,23 +0,0 @@
<div class="flex flex-col space-y-1">
@if($row->course_events_count > 0)
<div>
<x-button class="whitespace-nowrap" xs amber wire:click="courseSearch({{ $row->id }})">
{{ __('Show dates') }} [{{ $row->course_events_count }}]
</x-button>
</div>
@else
<div>
<x-button class="whitespace-nowrap" xs outline wire:click="courseSearch({{ $row->id }})">
{{ __('Show dates') }}
</x-button>
</div>
@endif
@can('update', $row)
<div>
<x-button class="whitespace-nowrap" amber xs :href="route('course.form.course', ['course' => $row])">
<i class="fa fa-thin fa-edit"></i>
{{ __('Edit') }}
</x-button>
</div>
@endcan
</div>

View File

@@ -1,6 +0,0 @@
<div class="w-full mb-4 md:w-auto md:mb-0">
<x-button :href="route('course.form.course')">
<i class="fa fa-thin fa-plus"></i>
{{ __('Register course') }}
</x-button>
</div>

View File

@@ -1,6 +0,0 @@
<div class="flex items-center space-x-2">
<img class="h-12" src="{{ $row->lecturer->getFirstMediaUrl('avatar', 'thumb') }}" alt="{{ $row->lecturer->name }}">
<div>
{{ $row->lecturer->name }}
</div>
</div>

View File

@@ -1,5 +0,0 @@
<div class="flex items-center">
@foreach($row->tags as $tag)
<x-badge class="whitespace-nowrap">{{ $tag->name }}</x-badge>
@endforeach
</div>

View File

@@ -1,15 +0,0 @@
<div class="flex flex-col space-y-1">
<div>
<x-button xs class="whitespace-nowrap" amber
wire:click="viewHistoryModal({{ $row->id }})">{{ __('Register') }}</x-button>
</div>
@can('update', $row)
<div>
<x-button xs class="whitespace-nowrap" amber
:href="route('course.form.courseEvent', ['courseEvent' => $row])">
<i class="fa-thin fa-edit"></i>
{{ __('Edit') }}
</x-button>
</div>
@endcan
</div>

View File

@@ -1,5 +0,0 @@
<div class="flex space-x-1">
@foreach($row->course->categories as $category)
<x-badge class="whitespace-nowrap">{{ $category->name }}</x-badge>
@endforeach
</div>

View File

@@ -1,6 +0,0 @@
<div class="flex items-center space-x-2">
<img class="h-12" src="{{ $row->course->lecturer->getFirstMediaUrl('avatar', 'thumb') }}" alt="{{ $row->course->lecturer->name }}">
<div>
{{ $row->course->lecturer->name }}
</div>
</div>

View File

@@ -1,59 +0,0 @@
<div class="flex flex-col space-y-1">
<div>
@if($row->courses_count > 0)
<x-button
xs amber wire:click="lecturerSearch({{ $row->id }})">
<i class="fa fa-thin fa-calendar mr-2"></i>
{{ __('Show dates') }} ({{ $row->courses_events_count }})
</x-button>
@endif
</div>
<div>
@if($row->courses_count < 1)
<x-button
xs outlined wire:click="lecturerSearch({{ $row->id }})">
<i class="fa fa-thin fa-calendar mr-2"></i>
{{ __('Show dates') }} ({{ $row->courses_events_count }})
</x-button>
@endif
</div>
<div>
@if($row->library_items_count > 0)
<x-button
xs amber wire:click="lecturerSearch({{ $row->id }}, false)">
<i class="fa fa-thin fa-book mr-2"></i>
{{ __('Show content') }} ({{ $row->library_items_count }})
</x-button>
@endif
</div>
<div>
@if($row->library_items_count < 1)
<x-button
xs outlined wire:click="lecturerSearch({{ $row->id }}, false)">
<i class="fa fa-thin fa-book mr-2"></i>
{{ __('Show content') }} ({{ $row->library_items_count }})
</x-button>
@endif
</div>
<div>
<x-button
xs
:href="route('school.landingPage.lecturer', ['country' => $country, 'lecturer' => $row->slug])"
black>
<i class="fa fa-thin fa-browser mr-2"></i>
{{ __('Show landing page') }}
</x-button>
</div>
<div>
@if($row->created_by === auth()->id())
<x-button
:href="route('contentCreator.form', ['country' => $country, 'lecturer' => $row->id])"
xs
amber
>
<i class="fa fa-thin fa-edit mr-2"></i>
{{ __('Edit') }}
</x-button>
@endif
</div>
</div>

View File

@@ -1,6 +0,0 @@
<div class="w-full mb-4 md:w-auto md:mb-0">
<x-button :href="route('contentCreator.form', ['country' => $country, 'lecturer' => null])">
<i class="fa fa-thin fa-plus"></i>
{{ __('Register lecturer') }}
</x-button>
</div>

View File

@@ -1,58 +0,0 @@
<div class="flex flex-col space-y-1">
<div>
@if(str($row->value)->contains('http'))
<x-button xs amber :href="$row->value" target="_blank">
<i class="fa fa-thin fa-book-open mr-2"></i>
{{ __('Open') }}
</x-button>
@endif
</div>
<div>
@if($row->type === 'downloadable_file')
<x-button xs amber :href="$row->getFirstMediaUrl('single_file')" target="_blank">
<i class="fa fa-thin fa-download mr-2"></i>
{{ __('Download') }}
</x-button>
@endif
</div>
<div>
@if($row->type === 'podcast_episode')
<x-button xs amber :href="$row->episode->data['link']" target="_blank">
<i class="fa fa-thin fa-headphones mr-2"></i>
{{ __('Listen') }}
</x-button>
@endif
</div>
<div>
@if($row->type === 'markdown_article')
<x-button xs amber :href="route('article.view', [$row])">
<i class="fa fa-thin fa-newspaper mr-2"></i>
{{ __('Read') }}
</x-button>
@endif
</div>
<div>
@if($row->type !== 'markdown_article')
<x-button
x-data="{
textToCopy: '{{ url()->route('library.table.libraryItems', ['country' => 'de', 'table' => ['filters' => ['id' => $row->id]]]) }}',
}"
@click.prevent="window.navigator.clipboard.writeText(textToCopy);window.$wireui.notify({title:'{{ __('Share url copied!') }}',icon:'success'});"
xs black>
<i class="fa fa-thin fa-copy mr-2"></i>
{{ __('Share link') }}
</x-button>
@else
<x-button
x-data="{
textToCopy: '{{ url()->route('library.table.libraryItems', ['country' => 'de', 'table' => ['filters' => ['id' => $row->id]]]) }}',
}"
@click.prevent="window.navigator.clipboard.writeText(textToCopy);window.$wireui.notify({title:'{{ __('Share url copied!') }}',icon:'success'});"
xs black>
<i class="fa fa-thin fa-copy mr-2"></i>
{{ __('Share link') }}
</x-button>
@endif
</div>
</div>

View File

@@ -1,3 +0,0 @@
<div class="w-12 h-12">
<img class="object-cover" src="{{ $row->getFirstMediaUrl('main', 'thumb') }}" alt="{{ $row->name }}">
</div>

Some files were not shown because too many files have changed in this diff Show More