trypost/app/Http/Middleware/App/HandleInertiaRequests.php
Paulo Castellano 0514ce677b feat(billing): clear trial_ends_at on subscription created + add tests
- StripeEventListener::handleSubscriptionCreated nulls account.trial_ends_at
  when a Stripe subscription is created. Prevents 'Trial' badge from
  lingering for users who convert mid-generic-trial to paid.
- Drop unused trialDays global Inertia prop (no frontend consumers after
  /subscribe redesign).

Tests added (10 new, 0 regressions, 1533 total):
- AccountTest: isOnTrial + activeTrialEndsAt across 4 scenarios
  (no trial, generic only, subscription only, both — subscription wins)
- StripeEventListenerTest: subscription created clears generic trial
- TrialMiddlewareAccessTest: trialing-with-card subscription passes
- BillingControllerTest: index exposes onTrial/trialEndsAt for the 3
  trial states (generic-only, subscription-only, paying); subscribe
  page no longer exposes trialDays prop
2026-05-14 20:23:35 -03:00

66 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Middleware\App;
use App\Http\Resources\App\HandleInertiaRequests\AuthAccountResource;
use App\Http\Resources\App\HandleInertiaRequests\AuthPlanResource;
use App\Http\Resources\App\HandleInertiaRequests\AuthUserResource;
use App\Http\Resources\App\HandleInertiaRequests\AuthWorkspaceResource;
use App\Models\Plan;
use Illuminate\Http\Request;
use Inertia\Middleware;
class HandleInertiaRequests extends Middleware
{
protected $rootView = 'app';
public function version(Request $request): ?string
{
return parent::version($request);
}
/**
* @return array<string, mixed>
*/
public function share(Request $request): array
{
$user = $request->user();
$currentWorkspace = $user?->currentWorkspace?->load('media');
$account = $user?->account;
$isSelfHosted = (bool) config('trypost.self_hosted');
return [
...parent::share($request),
'name' => config('app.name'),
'auth' => [
'user' => $user ? AuthUserResource::make($user) : null,
'currentWorkspace' => $currentWorkspace ? AuthWorkspaceResource::make($currentWorkspace, $user) : null,
'workspaces' => $user
? $user->workspaces()->with('media')->get()->map(fn ($ws) => AuthWorkspaceResource::summary($ws))
: [],
'account' => $account ? AuthAccountResource::make($account) : null,
'plan' => $account && $account->plan ? AuthPlanResource::make($account, $account->plan) : null,
'hasActiveSubscription' => $account ? $account->hasActiveSubscription() : false,
],
'usage' => $account && ! $isSelfHosted ? $account->usage() : null,
'features' => $account && ! $isSelfHosted ? $account->featureLimits() : null,
'plans' => $isSelfHosted ? [] : Plan::active()->orderBy('sort')->get(),
'sidebarOpen' => ! $request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true',
'flash' => $request->session()->get('flash', []),
'applicationUrl' => config('app.url'),
'env' => config('app.env'),
'locale' => app()->getLocale(),
'languages' => collect(config('languages.available'))->map(fn ($name, $code) => [
'code' => $code,
'name' => $name,
])->values()->all(),
'aiEnabled' => ! empty(config('services.gemini.api_key')) || ! empty(config('services.openai.api_key')),
'selfHosted' => $isSelfHosted,
'googleAuthEnabled' => config('trypost.google_auth_enabled'),
'githubAuthEnabled' => config('trypost.github_auth_enabled'),
];
}
}