|
| 1 | +<?php |
| 2 | + |
| 3 | +declare(strict_types=1); |
| 4 | + |
| 5 | +namespace App\Livewire\Components; |
| 6 | + |
| 7 | +use App\Enums\PaymentType; |
| 8 | +use App\Enums\TransactionType; |
| 9 | +use App\Models\Transaction; |
| 10 | +use App\Models\User; |
| 11 | +use Filament\Forms; |
| 12 | +use Filament\Forms\Concerns\InteractsWithForms; |
| 13 | +use Filament\Forms\Contracts\HasForms; |
| 14 | +use Filament\Forms\Form; |
| 15 | +use Filament\Notifications\Notification; |
| 16 | +use Illuminate\Contracts\View\View; |
| 17 | +use Illuminate\Support\Facades\Auth; |
| 18 | +use Illuminate\Support\Facades\Cache; |
| 19 | +use Illuminate\Support\Facades\Log; |
| 20 | +use Livewire\Component; |
| 21 | +use NotchPay\Exceptions\ApiException; |
| 22 | +use NotchPay\NotchPay; |
| 23 | +use NotchPay\Payment; |
| 24 | + |
| 25 | +/** |
| 26 | + * @property-read Form $form |
| 27 | + */ |
| 28 | +final class SponsorSubscription extends Component implements HasForms |
| 29 | +{ |
| 30 | + use InteractsWithForms; |
| 31 | + |
| 32 | + public ?array $data = []; |
| 33 | + |
| 34 | + public function mount(): void |
| 35 | + { |
| 36 | + $auth = Auth::user(); |
| 37 | + |
| 38 | + $this->form->fill([ |
| 39 | + 'email' => $auth?->email, |
| 40 | + 'name' => $auth?->name, |
| 41 | + 'website' => $auth?->website, |
| 42 | + 'profile' => 'developer', |
| 43 | + 'currency' => 'xaf', |
| 44 | + ]); |
| 45 | + } |
| 46 | + |
| 47 | + public function form(Form $form): Form |
| 48 | + { |
| 49 | + return $form |
| 50 | + ->schema([ |
| 51 | + Forms\Components\TextInput::make('name') |
| 52 | + ->label(__('validation.attributes.name')) |
| 53 | + ->minLength(5) |
| 54 | + ->required(), |
| 55 | + Forms\Components\TextInput::make('email') |
| 56 | + ->label(__('validation.attributes.email')) |
| 57 | + ->email() |
| 58 | + ->required(), |
| 59 | + Forms\Components\ToggleButtons::make('profile') |
| 60 | + ->label(__('pages/sponsoring.sponsor_form.profile')) |
| 61 | + ->options([ |
| 62 | + 'developer' => __('validation.attributes.freelance'), |
| 63 | + 'company' => __('validation.attributes.company'), |
| 64 | + ]) |
| 65 | + ->icons([ |
| 66 | + 'developer' => 'phosphor-dev-to-logo-duotone', |
| 67 | + 'company' => 'phosphor-buildings-duotone', |
| 68 | + ]) |
| 69 | + ->grouped(), |
| 70 | + Forms\Components\TextInput::make('website') |
| 71 | + ->label(__('global.website')) |
| 72 | + ->prefixIcon('heroicon-m-globe-alt') |
| 73 | + ->url(), |
| 74 | + Forms\Components\Group::make() |
| 75 | + ->schema([ |
| 76 | + Forms\Components\Select::make('currency') |
| 77 | + ->label(__('validation.attributes.currency')) |
| 78 | + ->live() |
| 79 | + ->native() |
| 80 | + ->options([ |
| 81 | + 'xaf' => 'XAF', |
| 82 | + 'eur' => 'EUR', |
| 83 | + 'usd' => 'USD', |
| 84 | + ]), |
| 85 | + Forms\Components\TextInput::make('amount') |
| 86 | + ->label(__('validation.attributes.amount')) |
| 87 | + ->integer() |
| 88 | + ->required() |
| 89 | + ->afterStateUpdated(fn (?int $state) => $state ? abs($state) : 0) |
| 90 | + ->prefix(fn (Forms\Get $get) => match ($get('currency')) { |
| 91 | + 'usd' => '$', |
| 92 | + default => null |
| 93 | + }) |
| 94 | + ->suffix(fn (Forms\Get $get) => match ($get('currency')) { |
| 95 | + 'eur' => '€', |
| 96 | + 'xaf' => 'FCFA', |
| 97 | + default => null, |
| 98 | + }) |
| 99 | + ->columnSpan(3), |
| 100 | + ]) |
| 101 | + ->columns(4) |
| 102 | + ->columnSpanFull(), |
| 103 | + ]) |
| 104 | + ->statePath('data') |
| 105 | + ->columns(); |
| 106 | + } |
| 107 | + |
| 108 | + public function submit(): void |
| 109 | + { |
| 110 | + $this->validate(); |
| 111 | + |
| 112 | + $email = data_get($this->form->getState(), 'email'); |
| 113 | + $amount = data_get($this->form->getState(), 'amount'); |
| 114 | + |
| 115 | + /** @var User $user */ |
| 116 | + $user = Auth::check() ? Auth::user() : User::findByEmailAddress(config('lcm.support_email')); |
| 117 | + |
| 118 | + NotchPay::setApiKey(apiKey: config('lcm.notch-pay-public-token')); |
| 119 | + |
| 120 | + try { |
| 121 | + $payload = Payment::initialize([ |
| 122 | + 'amount' => $amount, |
| 123 | + 'email' => $email, |
| 124 | + 'name' => data_get($this->form->getState(), 'name'), |
| 125 | + 'currency' => data_get($this->form->getState(), 'currency'), |
| 126 | + 'reference' => $user->id.'-'.$user->username().'-'.uniqid(), |
| 127 | + 'callback' => route('notchpay-callback'), |
| 128 | + 'description' => __('Soutien de la communauté Laravel & PHP Cameroun.'), |
| 129 | + ]); |
| 130 | + |
| 131 | + Transaction::query()->create([ |
| 132 | + 'amount' => $amount, |
| 133 | + 'status' => $payload->transaction->status, |
| 134 | + 'transaction_reference' => $payload->transaction->reference, |
| 135 | + 'user_id' => $user->id, |
| 136 | + 'fees' => $payload->transaction->fee, |
| 137 | + 'type' => TransactionType::ONETIME->value, |
| 138 | + 'metadata' => [ |
| 139 | + 'currency' => $payload->transaction->currency, |
| 140 | + 'reference' => $payload->transaction->reference, |
| 141 | + 'merchant' => [ |
| 142 | + 'reference' => $payload->transaction->merchant_reference, |
| 143 | + 'customer' => $payload->transaction->customer, |
| 144 | + 'laravel_cm_id' => Auth::id() ?? null, |
| 145 | + 'profile' => data_get($this->form->getState(), 'profile'), |
| 146 | + ], |
| 147 | + 'initiated_at' => $payload->transaction->created_at, |
| 148 | + 'description' => $payload->transaction->description, |
| 149 | + 'for' => PaymentType::SPONSORING->value, |
| 150 | + ], |
| 151 | + ]); |
| 152 | + |
| 153 | + $this->redirect($payload->authorization_url); // @phpstan-ignore-line |
| 154 | + } catch (ApiException $e) { |
| 155 | + Log::error($e->getMessage()); |
| 156 | + |
| 157 | + Notification::make() |
| 158 | + ->title(__('notifications.sponsor_error_title')) |
| 159 | + ->body(__('notifications.sponsor_error_body')) |
| 160 | + ->danger() |
| 161 | + ->send(); |
| 162 | + } |
| 163 | + } |
| 164 | + |
| 165 | + public function render(): View |
| 166 | + { |
| 167 | + return view('livewire.components.sponsor-subscription', [ |
| 168 | + 'sponsors' => Cache::remember( |
| 169 | + key: 'sponsors', |
| 170 | + ttl: now()->addWeek(), |
| 171 | + callback: fn () => Transaction::with(['user', 'user.media']) |
| 172 | + ->scopes('complete') |
| 173 | + ->distinct() |
| 174 | + ->get(['id', 'user_id', 'metadata']) |
| 175 | + ), |
| 176 | + ]); |
| 177 | + } |
| 178 | +} |
0 commit comments