chore: Remove MetricsWave tracking integration
MetricsWave visit tracker, event webhooks, and all funnel tracking (lead, onboarding, import) are no longer needed.
This commit is contained in:
parent
e81c4345a0
commit
1c425da330
|
|
@ -6,7 +6,6 @@ use App\Http\Requests\StoreUserLeadRequest;
|
|||
use App\Models\UserLead;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class UserLeadController extends Controller
|
||||
{
|
||||
|
|
@ -18,8 +17,6 @@ class UserLeadController extends Controller
|
|||
$validated = $request->validated();
|
||||
$lead = UserLead::create($validated);
|
||||
|
||||
$this->trackLeadCreatedEvent($validated['email']);
|
||||
|
||||
$redirectUrl = config('landing.lead_redirect_url');
|
||||
|
||||
if ($redirectUrl) {
|
||||
|
|
@ -30,19 +27,4 @@ class UserLeadController extends Controller
|
|||
|
||||
return to_route('home')->with('success', 'Thank you for your interest!');
|
||||
}
|
||||
|
||||
protected function trackLeadCreatedEvent(string $email): void
|
||||
{
|
||||
$eventUuid = config('landing.lead_funnel_event_uuid');
|
||||
|
||||
if (! $eventUuid || app()->environment('local', 'testing')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Http::withoutVerifying()
|
||||
->timeout(5)
|
||||
->post("https://metricswave.com/webhooks/{$eventUuid}", [
|
||||
'step' => 'Lead Created',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,15 +26,4 @@ return [
|
|||
|
||||
'lead_redirect_url' => env('LEAD_REDIRECT_URL', null),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Lead Funnel Event UUID
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The MetricsWave event UUID for tracking lead funnel events.
|
||||
|
|
||||
*/
|
||||
|
||||
'lead_funnel_event_uuid' => env('LEAD_FUNNEL_EVENT_UUID', '9668a06c-dee9-47a8-9bee-eaaa2a3a5915'),
|
||||
|
||||
];
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import {
|
|||
} from '@/components/ui/drawer';
|
||||
import { Progress } from '@/components/ui/progress';
|
||||
import { useEncryptionKey } from '@/contexts/encryption-key-context';
|
||||
import { IMPORT_FUNNEL_EVENT_UUID } from '@/lib/constants';
|
||||
import { importKey } from '@/lib/crypto';
|
||||
import {
|
||||
autoDetectColumns,
|
||||
|
|
@ -22,7 +21,6 @@ import {
|
|||
} from '@/lib/import-config-storage';
|
||||
import { getStoredKey } from '@/lib/key-storage';
|
||||
import { evaluateRulesForNewTransaction } from '@/lib/rule-engine';
|
||||
import { useTrackEvent } from '@/lib/track-event';
|
||||
import { transactionSyncService } from '@/services/transaction-sync';
|
||||
import { type Account, type Bank } from '@/types/account';
|
||||
import { type AutomationRule } from '@/types/automation-rule';
|
||||
|
|
@ -34,7 +32,7 @@ import {
|
|||
type ImportState,
|
||||
} from '@/types/import';
|
||||
import { router } from '@inertiajs/react';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { ImportStepAccount } from './import-step-account';
|
||||
import { ImportStepMapping } from './import-step-mapping';
|
||||
|
|
@ -61,14 +59,6 @@ interface ImportError {
|
|||
error: string;
|
||||
}
|
||||
|
||||
type ImportFunnelStep =
|
||||
| 'Open'
|
||||
| 'Choose account'
|
||||
| 'Set file'
|
||||
| 'Set mapping'
|
||||
| 'Confirm Preview'
|
||||
| 'Finish';
|
||||
|
||||
export function ImportTransactionsDrawer({
|
||||
accounts = [],
|
||||
categories = [],
|
||||
|
|
@ -79,8 +69,6 @@ export function ImportTransactionsDrawer({
|
|||
onImportComplete,
|
||||
}: ImportTransactionsDrawerProps) {
|
||||
const { isKeySet } = useEncryptionKey();
|
||||
const trackEvent = useTrackEvent();
|
||||
const trackedStepsRef = useRef<Set<ImportFunnelStep>>(new Set());
|
||||
const [isImporting, setIsImporting] = useState(false);
|
||||
const [importProgress, setImportProgress] = useState(0);
|
||||
const [importTotal, setImportTotal] = useState(0);
|
||||
|
|
@ -117,20 +105,8 @@ export function ImportTransactionsDrawer({
|
|||
}
|
||||
}, [state.selectedAccountId, accounts]);
|
||||
|
||||
const trackFunnelStep = useCallback(
|
||||
(step: ImportFunnelStep) => {
|
||||
if (!trackedStepsRef.current.has(step)) {
|
||||
trackedStepsRef.current.add(step);
|
||||
trackEvent(IMPORT_FUNNEL_EVENT_UUID, { step });
|
||||
}
|
||||
},
|
||||
[trackEvent],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
trackFunnelStep('Open');
|
||||
} else {
|
||||
if (!open) {
|
||||
setState({
|
||||
step: ImportStep.SelectAccount,
|
||||
selectedAccountId: null,
|
||||
|
|
@ -150,9 +126,8 @@ export function ImportTransactionsDrawer({
|
|||
setIsImporting(false);
|
||||
setError(null);
|
||||
setSelectedAccount(null);
|
||||
trackedStepsRef.current.clear();
|
||||
}
|
||||
}, [open, trackFunnelStep]);
|
||||
}, [open]);
|
||||
|
||||
const handleAccountSelect = (accountId: number) => {
|
||||
setState((prev) => ({ ...prev, selectedAccountId: accountId }));
|
||||
|
|
@ -322,7 +297,6 @@ export function ImportTransactionsDrawer({
|
|||
transactions: transactionsWithDuplicateCheck,
|
||||
step: ImportStep.Preview,
|
||||
}));
|
||||
trackFunnelStep('Set mapping');
|
||||
} catch (err) {
|
||||
setError(
|
||||
err instanceof Error
|
||||
|
|
@ -333,8 +307,6 @@ export function ImportTransactionsDrawer({
|
|||
};
|
||||
|
||||
const handleConfirmImport = async () => {
|
||||
trackFunnelStep('Confirm Preview');
|
||||
|
||||
if (!isKeySet) {
|
||||
setError('Please unlock your encryption key first');
|
||||
return;
|
||||
|
|
@ -535,10 +507,6 @@ export function ImportTransactionsDrawer({
|
|||
|
||||
console.log('Import complete:', { successCount, errorCount, total });
|
||||
|
||||
if (successCount > 0) {
|
||||
trackFunnelStep('Finish');
|
||||
}
|
||||
|
||||
if (errorCount === 0 && successCount > 0) {
|
||||
const message =
|
||||
uncategorizedCount > 0
|
||||
|
|
@ -675,7 +643,6 @@ export function ImportTransactionsDrawer({
|
|||
selectedAccountId={state.selectedAccountId}
|
||||
onAccountSelect={handleAccountSelect}
|
||||
onNext={() => {
|
||||
trackFunnelStep('Choose account');
|
||||
moveToStep(ImportStep.UploadFile);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -686,7 +653,6 @@ export function ImportTransactionsDrawer({
|
|||
file={state.file}
|
||||
onFileSelect={handleFileSelect}
|
||||
onNext={() => {
|
||||
trackFunnelStep('Set file');
|
||||
moveToStep(ImportStep.MapColumns);
|
||||
}}
|
||||
onBack={() => moveToStep(ImportStep.SelectAccount)}
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
export const LEAD_FUNNEL_EVENT_UUID = '9668a06c-dee9-47a8-9bee-eaaa2a3a5915';
|
||||
export const IMPORT_FUNNEL_EVENT_UUID = 'eea25dce-75ef-4959-b975-a7e9094b3ef5';
|
||||
export const ONBOARDING_FUNNEL_EVENT_UUID =
|
||||
'8a10c1da-080b-44cc-8dcf-78734b29106c';
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
import type { SharedData } from '@/types';
|
||||
import { usePage } from '@inertiajs/react';
|
||||
|
||||
export interface TrackEventPayload {
|
||||
step: string;
|
||||
user_id?: string | number;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface TrackEventOptions {
|
||||
method?: 'GET' | 'POST';
|
||||
}
|
||||
|
||||
function isLocalEnvironment(): boolean {
|
||||
if (typeof window === 'undefined') return true;
|
||||
const hostname = window.location.hostname;
|
||||
return hostname === 'localhost' || hostname.endsWith('.test');
|
||||
}
|
||||
|
||||
export async function trackEvent(
|
||||
eventUuid: string,
|
||||
payload: TrackEventPayload,
|
||||
options: TrackEventOptions = {},
|
||||
): Promise<void> {
|
||||
const { method = 'POST' } = options;
|
||||
|
||||
if (isLocalEnvironment()) {
|
||||
console.log('[Track Event]', {
|
||||
eventUuid,
|
||||
method,
|
||||
payload,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const url = `https://metricswave.com/webhooks/${eventUuid}`;
|
||||
|
||||
if (method === 'GET') {
|
||||
const queryParams = new URLSearchParams();
|
||||
Object.entries(payload).forEach(([key, value]) => {
|
||||
if (value !== undefined && value !== null) {
|
||||
queryParams.append(key, String(value));
|
||||
}
|
||||
});
|
||||
await fetch(`${url}?${queryParams.toString()}`, {
|
||||
keepalive: true,
|
||||
});
|
||||
} else {
|
||||
await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
keepalive: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function useTrackEvent() {
|
||||
const { auth } = usePage<SharedData>().props;
|
||||
|
||||
return (
|
||||
eventUuid: string,
|
||||
payload: Omit<TrackEventPayload, 'user_id'>,
|
||||
options?: TrackEventOptions,
|
||||
) => {
|
||||
const finalPayload: TrackEventPayload = {
|
||||
...payload,
|
||||
user_id: auth?.user?.id,
|
||||
};
|
||||
return trackEvent(eventUuid, finalPayload, options);
|
||||
};
|
||||
}
|
||||
|
|
@ -17,8 +17,6 @@ import {
|
|||
useOnboardingState,
|
||||
} from '@/hooks/use-onboarding-state';
|
||||
import OnboardingLayout from '@/layouts/onboarding-layout';
|
||||
import { ONBOARDING_FUNNEL_EVENT_UUID } from '@/lib/constants';
|
||||
import { useTrackEvent } from '@/lib/track-event';
|
||||
import { type Bank } from '@/types/account';
|
||||
import { Head } from '@inertiajs/react';
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
|
@ -49,9 +47,7 @@ export default function Onboarding({
|
|||
hasEncryptionSetup,
|
||||
}: OnboardingProps) {
|
||||
const { sync } = useSyncContext();
|
||||
const trackEvent = useTrackEvent();
|
||||
const hasSyncedRef = useRef(false);
|
||||
const trackedStepsRef = useRef<Set<OnboardingStep>>(new Set());
|
||||
|
||||
// Sync banks on mount to ensure IndexedDB has the latest data
|
||||
useEffect(() => {
|
||||
|
|
@ -75,13 +71,6 @@ export default function Onboarding({
|
|||
hasEncryptionSetup,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!trackedStepsRef.current.has(currentStep)) {
|
||||
trackedStepsRef.current.add(currentStep);
|
||||
trackEvent(ONBOARDING_FUNNEL_EVENT_UUID, { step: currentStep });
|
||||
}
|
||||
}, [currentStep, trackEvent]);
|
||||
|
||||
const handleAccountCreated = async (account: CreatedAccount) => {
|
||||
addCreatedAccount(account);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ import {
|
|||
TooltipTrigger,
|
||||
} from '@/components/ui/tooltip';
|
||||
import { usePwaInstall } from '@/hooks/use-pwa-install';
|
||||
import { LEAD_FUNNEL_EVENT_UUID } from '@/lib/constants';
|
||||
import { trackEvent } from '@/lib/track-event';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { type SharedData } from '@/types';
|
||||
import { Plan } from '@/types/pricing';
|
||||
|
|
@ -31,7 +29,7 @@ import {
|
|||
TrendingUpIcon,
|
||||
ZapIcon,
|
||||
} from 'lucide-react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const LANDING_IMAGES = [
|
||||
{
|
||||
|
|
@ -161,7 +159,6 @@ export default function Welcome({
|
|||
const { appUrl, subscriptionsEnabled, pricing } =
|
||||
usePage<SharedData>().props;
|
||||
const planEntries = Object.entries(pricing.plans);
|
||||
const visitTrackedRef = useRef(false);
|
||||
const { isMobile } = usePwaInstall();
|
||||
|
||||
const [isPwa] = useState(() => {
|
||||
|
|
@ -179,16 +176,7 @@ export default function Welcome({
|
|||
useEffect(() => {
|
||||
if (isPwa) {
|
||||
router.visit('/dashboard');
|
||||
return;
|
||||
}
|
||||
|
||||
if (visitTrackedRef.current) {
|
||||
return;
|
||||
}
|
||||
visitTrackedRef.current = true;
|
||||
trackEvent(LEAD_FUNNEL_EVENT_UUID, {
|
||||
step: 'Visit',
|
||||
});
|
||||
}, [isPwa]);
|
||||
|
||||
if (isPwa) {
|
||||
|
|
|
|||
|
|
@ -58,11 +58,6 @@
|
|||
<body class="font-sans antialiased">
|
||||
@inertia
|
||||
|
||||
<script defer
|
||||
event-uuid="696e6c66-33e0-482c-aa4a-a21410ec38c8"
|
||||
src="https://tracker.metricswave.com/js/visits.js"
|
||||
></script>
|
||||
|
||||
<script>
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/sw.js', { scope: '/' });
|
||||
|
|
|
|||
Loading…
Reference in New Issue