|
7 | 7 | use App\Enums\PaymentType;
|
8 | 8 | use App\Enums\TransactionType;
|
9 | 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; |
10 | 16 | use Illuminate\Contracts\View\View;
|
11 | 17 | use Illuminate\Support\Facades\Auth;
|
| 18 | +use Illuminate\Support\Facades\Cache; |
12 | 19 | use Illuminate\Support\Facades\Log;
|
13 | 20 | use Livewire\Component;
|
| 21 | +use NotchPay\Exceptions\ApiException; |
14 | 22 | use NotchPay\NotchPay;
|
15 | 23 | use NotchPay\Payment;
|
16 | 24 |
|
17 |
| -final class SponsorSubscription extends Component |
| 25 | +/** |
| 26 | + * @property-read Form $form |
| 27 | + */ |
| 28 | +final class SponsorSubscription extends Component implements HasForms |
18 | 29 | {
|
19 |
| - public string $option = 'one-time'; |
| 30 | + use InteractsWithForms; |
20 | 31 |
|
21 |
| - public string $amount = ''; |
| 32 | + public ?array $data = []; |
22 | 33 |
|
23 |
| - public string $currency = 'XAF'; |
| 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 | + } |
24 | 46 |
|
25 |
| - public function chooseOption(string $option): void |
| 47 | + public function form(Form $form): Form |
26 | 48 | {
|
27 |
| - $this->option = $option; |
| 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(); |
28 | 106 | }
|
29 | 107 |
|
30 |
| - public function subscribe(): void |
| 108 | + public function submit(): void |
31 | 109 | {
|
32 |
| - $this->validate(['amount' => 'required']); |
| 110 | + $this->validate(); |
33 | 111 |
|
34 |
| - if (! Auth::check()) { |
35 |
| - $this->dispatch('openModal', component: 'modals.anonymous-sponsors', arguments: [ |
36 |
| - 'amount' => $this->amount, |
37 |
| - 'option' => $this->option, |
38 |
| - 'currency' => $this->currency, |
39 |
| - ]); |
| 112 | + $email = data_get($this->form->getState(), 'email'); |
| 113 | + $amount = data_get($this->form->getState(), 'amount'); |
40 | 114 |
|
41 |
| - return; |
42 |
| - } |
| 115 | + /** @var User $user */ |
| 116 | + $user = Auth::check() ? Auth::user() : User::findByEmailAddress(config('lcm.support_email')); |
43 | 117 |
|
44 | 118 | NotchPay::setApiKey(apiKey: config('lcm.notch-pay-public-token'));
|
45 | 119 |
|
46 | 120 | try {
|
47 | 121 | $payload = Payment::initialize([
|
48 |
| - 'amount' => $this->amount, |
49 |
| - 'email' => Auth::user()?->email, |
50 |
| - 'name' => Auth::user()?->name, |
51 |
| - 'currency' => $this->currency, |
52 |
| - 'reference' => Auth::id().'-'.Auth::user()?->username().'-'.uniqid(), |
| 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(), |
53 | 127 | 'callback' => route('notchpay-callback'),
|
54 | 128 | 'description' => __('Soutien de la communauté Laravel & PHP Cameroun.'),
|
55 | 129 | ]);
|
56 | 130 |
|
57 | 131 | Transaction::query()->create([
|
58 |
| - 'amount' => $this->amount, |
| 132 | + 'amount' => $amount, |
59 | 133 | 'status' => $payload->transaction->status,
|
60 | 134 | 'transaction_reference' => $payload->transaction->reference,
|
61 |
| - 'user_id' => Auth::id(), |
| 135 | + 'user_id' => $user->id, |
62 | 136 | 'fees' => $payload->transaction->fee,
|
63 |
| - 'type' => $this->option === 'one-time' |
64 |
| - ? TransactionType::ONETIME->value |
65 |
| - : TransactionType::RECURSIVE->value, |
| 137 | + 'type' => TransactionType::ONETIME->value, |
66 | 138 | 'metadata' => [
|
67 | 139 | 'currency' => $payload->transaction->currency,
|
68 | 140 | 'reference' => $payload->transaction->reference,
|
69 | 141 | 'merchant' => [
|
70 | 142 | 'reference' => $payload->transaction->merchant_reference,
|
71 |
| - 'name' => $payload->transaction->customer->name, |
72 |
| - 'email' => $payload->transaction->customer->email, |
73 |
| - 'phone' => $payload->transaction->customer->phone, |
74 |
| - 'laravel_cm_id' => Auth::id(), |
| 143 | + 'customer' => $payload->transaction->customer, |
| 144 | + 'laravel_cm_id' => Auth::id() ?? null, |
| 145 | + 'profile' => data_get($this->form->getState(), 'profile'), |
75 | 146 | ],
|
76 |
| - 'initiated_at' => $payload->transaction->initiated_at, |
| 147 | + 'initiated_at' => $payload->transaction->created_at, |
77 | 148 | 'description' => $payload->transaction->description,
|
78 | 149 | 'for' => PaymentType::SPONSORING->value,
|
79 | 150 | ],
|
80 | 151 | ]);
|
81 | 152 |
|
82 | 153 | $this->redirect($payload->authorization_url); // @phpstan-ignore-line
|
83 |
| - } catch (\NotchPay\Exceptions\ApiException $e) { |
| 154 | + } catch (ApiException $e) { |
84 | 155 | Log::error($e->getMessage());
|
85 |
| - session()->flash('error', __('Impossible de procéder au paiement, veuillez recommencer plus tard. Merci')); |
| 156 | + |
| 157 | + Notification::make() |
| 158 | + ->title(__('notifications.sponsor_error_title')) |
| 159 | + ->body(__('notifications.sponsor_error_body')) |
| 160 | + ->danger() |
| 161 | + ->send(); |
86 | 162 | }
|
87 | 163 | }
|
88 | 164 |
|
89 | 165 | public function render(): View
|
90 | 166 | {
|
91 |
| - return view('livewire.sponsor-subscription'); |
| 167 | + return view('livewire.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 | + ]); |
92 | 177 | }
|
93 | 178 | }
|
0 commit comments