-
Notifications
You must be signed in to change notification settings - Fork 0
Release v0.1.18 — Phase 18: Billing Page #249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
9ad015e
CONV-274: Create Billing page route
menvil 5fdbba7
Merge pull request #246 from menvil/feature/CONV-274-create-billing-p…
menvil 17bc30e
CONV-275: Create Billing page Livewire component
menvil 47035cc
Merge pull request #247 from menvil/feature/CONV-275-create-billing-p…
menvil 9051e77
CONV-276: Add current plan summary card
menvil f840191
CONV-277: Add credits balance card
menvil d691120
CONV-278: Add plan limits summary card
menvil bdac9c6
CONV-279: Add available plans section
menvil b588802
CONV-280: Highlight current plan
menvil da8a0e5
CONV-281: Add subscription checkout actions
menvil a8eae2a
CONV-282: Add checkout result notices
menvil eaee82e
CONV-283: Add credit packs section
menvil 08e8ceb
CONV-285: Add credit transaction history table
menvil 2aac18d
CONV-288: Add billing empty and error states
menvil 223e376
CONV-289: Add billing responsive layout
menvil 0108a14
CONV-290: Add billing page final smoke tests
menvil 5b0ad09
Merge pull request #248 from menvil/feature/CONV-276-add-current-plan…
menvil 49266ac
Fix billing page inline review issues
menvil 260650f
Merge pull request #250 from menvil/fix/billing-page-review
menvil File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace App\Actions\Billing; | ||
|
|
||
| use App\Billing\BillingPaymentService; | ||
| use App\Billing\CheckoutSessionDto; | ||
| use App\Models\User; | ||
| use App\Services\Billing\CreditPackRepository; | ||
| use Illuminate\Validation\ValidationException; | ||
|
|
||
| final class BuyCreditPackAction | ||
| { | ||
| public function __construct( | ||
| private readonly CreditPackRepository $packRepository, | ||
| private readonly BillingPaymentService $paymentService, | ||
| ) {} | ||
|
|
||
| public function handle(User $user, string $packKey, string $successUrl, string $cancelUrl): CheckoutSessionDto | ||
| { | ||
| $pack = $this->packRepository->find($packKey); | ||
|
|
||
| if ($pack === null) { | ||
| throw ValidationException::withMessages(['pack' => 'This credit pack is no longer available.']); | ||
| } | ||
|
|
||
| return $this->paymentService->createCreditPackCheckout( | ||
| user: $user, | ||
| pack: $pack, | ||
| successUrl: $successUrl, | ||
| cancelUrl: $cancelUrl, | ||
| ); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace App\Actions\Billing; | ||
|
|
||
| use App\Billing\BillingPaymentService; | ||
| use App\Billing\BillingPlanRepository; | ||
| use App\Billing\CheckoutSessionDto; | ||
| use App\Enums\Plan; | ||
| use App\Models\User; | ||
| use Illuminate\Validation\ValidationException; | ||
|
|
||
| final class StartSubscriptionCheckoutAction | ||
| { | ||
| public function __construct( | ||
| private readonly BillingPlanRepository $planRepository, | ||
| private readonly BillingPaymentService $paymentService, | ||
| ) {} | ||
|
|
||
| public function handle(User $user, string $planKey, string $successUrl, string $cancelUrl): CheckoutSessionDto | ||
| { | ||
| try { | ||
| $plan = Plan::from($planKey); | ||
| } catch (\ValueError) { | ||
| throw ValidationException::withMessages(['plan' => 'Invalid plan selected.']); | ||
| } | ||
|
|
||
| if ($plan === Plan::Free) { | ||
| throw ValidationException::withMessages(['plan' => 'Free plan does not require checkout.']); | ||
| } | ||
|
|
||
| if ($user->plan === $plan) { | ||
| throw ValidationException::withMessages(['plan' => 'You are already on this plan.']); | ||
| } | ||
|
|
||
| $billingPlan = $this->planRepository->findOrFail($planKey); | ||
|
|
||
| return $this->paymentService->createSubscriptionCheckout( | ||
| user: $user, | ||
| plan: $billingPlan, | ||
| successUrl: $successUrl, | ||
| cancelUrl: $cancelUrl, | ||
| ); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace App\Livewire\Billing; | ||
|
|
||
| use App\Actions\Billing\BuyCreditPackAction; | ||
| use App\Actions\Billing\StartSubscriptionCheckoutAction; | ||
| use App\Billing\BillingPlanDto; | ||
| use App\Billing\BillingPlanRepository; | ||
| use App\Contracts\Billing\CreditLedger; | ||
| use App\Data\Billing\CreditPackDto; | ||
| use App\Models\CreditTransaction; | ||
| use App\Models\User; | ||
| use App\Services\Billing\CreditPackRepository; | ||
| use App\Services\FeatureAccess\FeatureAccessService; | ||
| use App\Services\FeatureAccess\PlanLimit; | ||
| use Illuminate\Contracts\View\View; | ||
| use Illuminate\Pagination\LengthAwarePaginator; | ||
| use Illuminate\Support\Collection; | ||
| use Illuminate\Validation\ValidationException; | ||
| use Livewire\Attributes\Layout; | ||
| use Livewire\Attributes\Title; | ||
| use Livewire\Component; | ||
| use Livewire\WithPagination; | ||
|
|
||
| #[Layout('components.layouts.app')] | ||
| #[Title('Billing — ConvertAI')] | ||
| class BillingPage extends Component | ||
| { | ||
| use WithPagination; | ||
|
|
||
| public ?string $checkoutStatus = null; | ||
|
|
||
| public function mount(): void | ||
| { | ||
| $status = request()->query('checkout'); | ||
|
|
||
| if (in_array($status, ['success', 'cancelled'], true)) { | ||
| $this->checkoutStatus = $status; | ||
| } | ||
| } | ||
|
|
||
| public function getAuthUserProperty(): User | ||
| { | ||
| /** @var User */ | ||
| return auth()->user(); | ||
| } | ||
|
|
||
| public function getCreditsBalanceProperty(): int | ||
| { | ||
| return app(CreditLedger::class)->balance($this->authUser); | ||
| } | ||
|
|
||
| public function getPlanLimitsProperty(): PlanLimit | ||
| { | ||
| return app(FeatureAccessService::class)->limits($this->authUser); | ||
| } | ||
|
|
||
| public function getApiAccessProperty(): bool | ||
| { | ||
| return app(FeatureAccessService::class)->allows($this->authUser, 'api_access'); | ||
| } | ||
|
|
||
| public function getBatchConversionProperty(): bool | ||
| { | ||
| return app(FeatureAccessService::class)->allows($this->authUser, 'batch_conversion'); | ||
| } | ||
|
|
||
| /** @return BillingPlanDto[] */ | ||
| public function getPlansProperty(): array | ||
| { | ||
| return app(BillingPlanRepository::class)->all(); | ||
| } | ||
|
|
||
| /** @return Collection<int, CreditPackDto> */ | ||
| public function getCreditPacksProperty(): Collection | ||
| { | ||
| return app(CreditPackRepository::class)->all(); | ||
| } | ||
|
|
||
| /** @return LengthAwarePaginator<CreditTransaction> */ | ||
| public function getTransactionsProperty() | ||
| { | ||
| return CreditTransaction::query() | ||
| ->where('user_id', $this->authUser->id) | ||
| ->latest() | ||
| ->paginate(10); | ||
| } | ||
|
|
||
| public function startSubscriptionCheckout(string $planKey): void | ||
| { | ||
| $session = app(StartSubscriptionCheckoutAction::class)->handle( | ||
| user: $this->authUser, | ||
| planKey: $planKey, | ||
| successUrl: route('billing', ['checkout' => 'success']), | ||
| cancelUrl: route('billing', ['checkout' => 'cancelled']), | ||
| ); | ||
|
|
||
| $this->redirect($session->url, navigate: false); | ||
| } | ||
|
|
||
| public function buyCreditPack(string $packKey): void | ||
| { | ||
| $session = app(BuyCreditPackAction::class)->handle( | ||
| user: $this->authUser, | ||
| packKey: $packKey, | ||
| successUrl: route('billing', ['checkout' => 'success']), | ||
| cancelUrl: route('billing', ['checkout' => 'cancelled']), | ||
| ); | ||
|
|
||
| $this->redirect($session->url, navigate: false); | ||
| } | ||
|
|
||
| public function openCustomerPortal(): void | ||
| { | ||
| throw ValidationException::withMessages(['portal' => 'Billing portal will be available after payment provider setup.']); | ||
| } | ||
|
|
||
| public function render(): View | ||
| { | ||
| return view('livewire.billing.billing-page'); | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.