trypost/app/Http/Resources/App/HandleInertiaRequests/AuthPlanResource.php
Paulo Castellano 96e1aa36b6 feat: GTM dataLayer context + checkout/purchase events
Backend exposes account and plan as proper Inertia resources so any
page can read them off shared props:

- AuthAccountResource — id, name, created_at
- AuthPlanResource — id, slug, name, interval (derived from the active
  Cashier subscription's stripe_price)

Both wired into HandleInertiaRequests::share so `auth.account` and
`auth.plan` are available everywhere.

Frontend pushes app + identity context to GTM's dataLayer on every
page load via initializeDataLayer (resources/js/datalayer.ts), and
useTracking gets begin_checkout/purchase wired in the billing flow.

The pushes are no-ops without GTM configured (the array still exists
in memory, nothing reads it). Self-hosted instances without GTM_ID
incur zero error noise. The GTM partials in app.blade.php were
already conditional on `config('services.gtm.id')`.

Processing.vue polls `auth` alongside `subscriptionActive` so
auth.plan.interval is fresh once the Stripe webhook creates the local
Subscription row (it doesn't exist yet at the initial render). The
watch fires only on the false → true transition; an onMounted
fallback redirects users that land on the page with an already-active
subscription without re-firing trackPurchase.
2026-05-06 10:14:17 -03:00

29 lines
695 B
PHP

<?php
declare(strict_types=1);
namespace App\Http\Resources\App\HandleInertiaRequests;
use App\Models\Account;
use App\Models\Plan;
class AuthPlanResource
{
/**
* @return array<string, mixed>
*/
public static function make(Account $account, Plan $plan): array
{
$subscription = $account->subscription(Account::SUBSCRIPTION_NAME);
$interval = ($subscription && $subscription->stripe_price === $plan->stripe_yearly_price_id)
? 'yearly'
: 'monthly';
return [
'id' => $plan->id,
'slug' => $plan->slug->value,
'name' => $plan->name,
'interval' => $interval,
];
}
}