chore: tracking, gtm and more
This commit is contained in:
parent
843b3991ec
commit
7d95fd1efa
18 changed files with 172 additions and 8 deletions
|
|
@ -132,6 +132,9 @@ PINTEREST_CLIENT_ID=
|
|||
PINTEREST_CLIENT_SECRET=
|
||||
PINTEREST_CLIENT_REDIRECT="${APP_URL}/accounts/pinterest/callback"
|
||||
|
||||
# Google Tag Manager (optional - analytics)
|
||||
GTM_ID=
|
||||
|
||||
# PostHog (optional - analytics)
|
||||
POSTHOG_API_KEY=
|
||||
POSTHOG_HOST=https://us.i.posthog.com
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ public function store(Request $request): RedirectResponse
|
|||
}
|
||||
}
|
||||
|
||||
return redirect()->route('app.onboarding.role');
|
||||
session()->flash('auth_provider', 'email');
|
||||
|
||||
return redirect()->route('register.success');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
20
app/Http/Controllers/Auth/SignupSuccessController.php
Normal file
20
app/Http/Controllers/Auth/SignupSuccessController.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
class SignupSuccessController extends Controller
|
||||
{
|
||||
public function __invoke(Request $request): Response
|
||||
{
|
||||
return Inertia::render('auth/SignupSuccess', [
|
||||
'authProvider' => $request->session()->get('auth_provider', 'email'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -55,6 +55,8 @@ private function registerNewUser(\Laravel\Socialite\Contracts\User $googleUser):
|
|||
|
||||
Auth::login($user, remember: true);
|
||||
|
||||
return redirect()->route('app.onboarding.role');
|
||||
session()->flash('auth_provider', 'google');
|
||||
|
||||
return redirect()->route('register.success');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,8 +74,6 @@ public function publish(PostPlatform $postPlatform): array
|
|||
|
||||
private function publishTextPost(string $userId, string $accessToken, string $content): array
|
||||
{
|
||||
Log::info('Threads publishing text post', ['user_id' => $userId]);
|
||||
|
||||
// Step 1: Create container
|
||||
$containerResponse = Http::post("{$this->baseUrl}/{$userId}/threads", [
|
||||
'media_type' => 'TEXT',
|
||||
|
|
@ -99,8 +97,6 @@ private function publishTextPost(string $userId, string $accessToken, string $co
|
|||
|
||||
private function publishImagePost(string $userId, string $accessToken, ?string $content, $media): array
|
||||
{
|
||||
Log::info('Threads publishing image post', ['user_id' => $userId, 'image_url' => $media->url]);
|
||||
|
||||
// Step 1: Create container
|
||||
$containerResponse = Http::post("{$this->baseUrl}/{$userId}/threads", [
|
||||
'media_type' => 'IMAGE',
|
||||
|
|
|
|||
|
|
@ -104,6 +104,10 @@
|
|||
'redirect' => env('PINTEREST_CLIENT_REDIRECT'),
|
||||
],
|
||||
|
||||
'gtm' => [
|
||||
'id' => env('GTM_ID'),
|
||||
],
|
||||
|
||||
'posthog' => [
|
||||
'api_key' => env('POSTHOG_API_KEY'),
|
||||
'host' => env('POSTHOG_HOST', 'https://us.i.posthog.com'),
|
||||
|
|
|
|||
|
|
@ -55,6 +55,12 @@
|
|||
'google_login' => 'Log in with Google',
|
||||
'google_signup' => 'Sign up with Google',
|
||||
|
||||
'signup_success' => [
|
||||
'page_title' => 'Welcome',
|
||||
'title' => 'Setting up your account',
|
||||
'description' => 'This usually takes just a few seconds...',
|
||||
],
|
||||
|
||||
'login' => [
|
||||
'title' => 'Log in to your account',
|
||||
'description' => 'Enter your email and password below to log in',
|
||||
|
|
|
|||
|
|
@ -43,6 +43,12 @@
|
|||
'google_login' => 'Iniciar sesión con Google',
|
||||
'google_signup' => 'Registrarse con Google',
|
||||
|
||||
'signup_success' => [
|
||||
'page_title' => 'Bienvenido',
|
||||
'title' => 'Configurando tu cuenta',
|
||||
'description' => 'Esto suele tardar solo unos segundos...',
|
||||
],
|
||||
|
||||
'login' => [
|
||||
'title' => 'Inicia sesión en tu cuenta',
|
||||
'description' => 'Introduce tu correo y contraseña para iniciar sesión',
|
||||
|
|
|
|||
|
|
@ -55,6 +55,12 @@
|
|||
'google_login' => 'Entrar com Google',
|
||||
'google_signup' => 'Cadastrar com Google',
|
||||
|
||||
'signup_success' => [
|
||||
'page_title' => 'Bem-vindo',
|
||||
'title' => 'Configurando sua conta',
|
||||
'description' => 'Isso geralmente leva apenas alguns segundos...',
|
||||
],
|
||||
|
||||
'login' => [
|
||||
'title' => 'Entrar na sua conta',
|
||||
'description' => 'Digite seu email e senha abaixo para entrar',
|
||||
|
|
|
|||
51
resources/js/composables/useTracking.ts
Normal file
51
resources/js/composables/useTracking.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import posthog from '@/posthog';
|
||||
|
||||
const push = (data: Record<string, unknown>) => {
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
window.dataLayer.push(data);
|
||||
};
|
||||
|
||||
export const useTracking = () => ({
|
||||
trackSignUp: (authProvider: string) => {
|
||||
posthog.capture('user.signed_up', {
|
||||
auth_provider: authProvider,
|
||||
});
|
||||
|
||||
push({
|
||||
event: 'sign_up',
|
||||
method: authProvider,
|
||||
});
|
||||
},
|
||||
|
||||
trackBeginCheckout: (plan: { name: string; price: number; interval: string }) => {
|
||||
posthog.capture('checkout.started', {
|
||||
plan_name: plan.name,
|
||||
plan_price: plan.price,
|
||||
interval: plan.interval,
|
||||
});
|
||||
|
||||
push({
|
||||
event: 'begin_checkout',
|
||||
currency: 'USD',
|
||||
plan_name: plan.name,
|
||||
plan_price: plan.price,
|
||||
plan_interval: plan.interval,
|
||||
});
|
||||
},
|
||||
|
||||
trackPurchase: (plan: { name: string; price: number; interval: string }) => {
|
||||
posthog.capture('checkout.completed', {
|
||||
plan_name: plan.name,
|
||||
plan_price: plan.price,
|
||||
interval: plan.interval,
|
||||
});
|
||||
|
||||
push({
|
||||
event: 'purchase',
|
||||
currency: 'USD',
|
||||
plan_name: plan.name,
|
||||
plan_price: plan.price,
|
||||
plan_interval: plan.interval,
|
||||
});
|
||||
},
|
||||
});
|
||||
41
resources/js/pages/auth/SignupSuccess.vue
Normal file
41
resources/js/pages/auth/SignupSuccess.vue
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<script setup lang="ts">
|
||||
import { Head, router } from '@inertiajs/vue3';
|
||||
import { IconLoader2 } from '@tabler/icons-vue';
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
import { useTracking } from '@/composables/useTracking';
|
||||
import AuthBase from '@/layouts/AuthLayout.vue';
|
||||
import { role } from '@/routes/app/onboarding';
|
||||
|
||||
const props = defineProps<{
|
||||
authProvider: string;
|
||||
}>();
|
||||
|
||||
const { trackSignUp } = useTracking();
|
||||
|
||||
onMounted(() => {
|
||||
trackSignUp(props.authProvider);
|
||||
|
||||
setTimeout(() => {
|
||||
router.visit(role.url());
|
||||
}, 5000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Head :title="$t('auth.signup_success.page_title')" />
|
||||
|
||||
<AuthBase>
|
||||
<div class="flex flex-col items-center gap-4 text-center">
|
||||
<IconLoader2 class="size-8 animate-spin text-muted-foreground" />
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold tracking-tight">
|
||||
{{ $t('auth.signup_success.title') }}
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-muted-foreground">
|
||||
{{ $t('auth.signup_success.description') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</AuthBase>
|
||||
</template>
|
||||
6
resources/js/types/globals.d.ts
vendored
6
resources/js/types/globals.d.ts
vendored
|
|
@ -1,5 +1,11 @@
|
|||
import { AppPageProps } from '@/types/index';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
dataLayer: Record<string, unknown>[];
|
||||
}
|
||||
}
|
||||
|
||||
// Extend ImportMeta interface for Vite...
|
||||
declare module 'vite/client' {
|
||||
interface ImportMetaEnv {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
|
||||
@include('partials.gtm')
|
||||
|
||||
{{-- Inline script to detect system dark mode preference and apply it immediately --}}
|
||||
<script>
|
||||
(function() {
|
||||
|
|
@ -44,6 +46,7 @@
|
|||
@inertiaHead
|
||||
</head>
|
||||
<body class="font-sans antialiased">
|
||||
@include('partials.gtm-noscript')
|
||||
@inertia
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
6
resources/views/partials/gtm-noscript.blade.php
Normal file
6
resources/views/partials/gtm-noscript.blade.php
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
@if(config('services.gtm.id'))
|
||||
<!-- Google Tag Manager (noscript) -->
|
||||
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id={{ config('services.gtm.id') }}"
|
||||
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
|
||||
<!-- End Google Tag Manager (noscript) -->
|
||||
@endif
|
||||
9
resources/views/partials/gtm.blade.php
Normal file
9
resources/views/partials/gtm.blade.php
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
@if(config('services.gtm.id'))
|
||||
<!-- Google Tag Manager -->
|
||||
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||
})(window,document,'script','dataLayer','{{ config('services.gtm.id') }}');</script>
|
||||
<!-- End Google Tag Manager -->
|
||||
@endif
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
use App\Http\Controllers\Auth\NewPasswordController;
|
||||
use App\Http\Controllers\Auth\PasswordResetLinkController;
|
||||
use App\Http\Controllers\Auth\RegisteredUserController;
|
||||
use App\Http\Controllers\Auth\SignupSuccessController;
|
||||
use App\Http\Controllers\Auth\SocialLoginController;
|
||||
use App\Http\Controllers\Auth\VerifyEmailController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
|
@ -51,6 +52,8 @@ function () {
|
|||
'middleware' => ['auth'],
|
||||
],
|
||||
function () {
|
||||
Route::get('/register/success', SignupSuccessController::class)->name('register.success');
|
||||
|
||||
Route::get('/verify-email', EmailVerificationPromptController::class)->name('verification.notice');
|
||||
|
||||
Route::get('/verify-email/{id}/{hash}', VerifyEmailController::class)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
$response->assertSessionHasNoErrors();
|
||||
$this->assertAuthenticated();
|
||||
$response->assertRedirect(route('app.onboarding.role', absolute: false));
|
||||
$response->assertRedirect(route('register.success', absolute: false));
|
||||
});
|
||||
|
||||
test('new users get a default workspace on registration', function () {
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
|
||||
$response = $this->get(route('auth.google.callback'));
|
||||
|
||||
$response->assertRedirect(route('app.onboarding.role'));
|
||||
$response->assertRedirect(route('register.success'));
|
||||
|
||||
$user = User::where('email', 'new@example.com')->first();
|
||||
expect($user)->not->toBeNull();
|
||||
|
|
|
|||
Loading…
Reference in a new issue