Add plausible
This commit is contained in:
parent
48f2c97487
commit
4857800fca
14 changed files with 118 additions and 6 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import { useState, useEffect, useCallback } from 'react';
|
||||
import pb from '../lib/pocketbase';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
|
||||
export interface AuthUser {
|
||||
id: string;
|
||||
|
|
@ -52,6 +53,7 @@ export function useAuth() {
|
|||
try {
|
||||
const result = await pb.collection('users').authWithPassword(email, password);
|
||||
setUser(recordToUser(result.record));
|
||||
trackEvent('Login', { method: 'email' });
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : 'Login failed';
|
||||
setError(msg);
|
||||
|
|
@ -73,6 +75,7 @@ export function useAuth() {
|
|||
// Auto-login after registration
|
||||
const result = await pb.collection('users').authWithPassword(email, password);
|
||||
setUser(recordToUser(result.record));
|
||||
trackEvent('Register');
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : 'Registration failed';
|
||||
setError(msg);
|
||||
|
|
@ -88,6 +91,7 @@ export function useAuth() {
|
|||
try {
|
||||
const result = await pb.collection('users').authWithOAuth2({ provider });
|
||||
setUser(recordToUser(result.record));
|
||||
trackEvent('Login', { method: provider });
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : 'OAuth login failed';
|
||||
setError(msg);
|
||||
|
|
@ -98,6 +102,7 @@ export function useAuth() {
|
|||
}, []);
|
||||
|
||||
const logout = useCallback(() => {
|
||||
trackEvent('Logout');
|
||||
pb.authStore.clear();
|
||||
setUser(null);
|
||||
}, []);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { useState, useCallback, useMemo } from 'react';
|
||||
import type { FeatureMeta, FeatureFilters } from '../types';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
|
||||
interface UseFiltersOptions {
|
||||
initialFilters: FeatureFilters;
|
||||
|
|
@ -29,6 +30,7 @@ export function useFilters({ initialFilters, features }: UseFiltersOptions) {
|
|||
(name: string) => {
|
||||
const meta = features.find((f) => f.name === name);
|
||||
if (!meta) return;
|
||||
trackEvent('Filter Add', { feature: name });
|
||||
if (meta.type === 'enum' && meta.values) {
|
||||
setFilters((prev) => ({ ...prev, [name]: [...meta.values!] }));
|
||||
} else if (meta.type === 'numeric' && meta.histogram) {
|
||||
|
|
@ -45,6 +47,7 @@ export function useFilters({ initialFilters, features }: UseFiltersOptions) {
|
|||
}, []);
|
||||
|
||||
const handleRemoveFilter = useCallback((name: string) => {
|
||||
trackEvent('Filter Remove', { feature: name });
|
||||
setFilters((prev) => {
|
||||
const next = { ...prev };
|
||||
delete next[name];
|
||||
|
|
@ -84,6 +87,7 @@ export function useFilters({ initialFilters, features }: UseFiltersOptions) {
|
|||
}, []);
|
||||
|
||||
const handleTogglePin = useCallback((name: string) => {
|
||||
trackEvent('Filter Pin', { feature: name });
|
||||
setPinnedFeature((prev) => (prev === name ? null : name));
|
||||
}, []);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useState, useCallback } from 'react';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import type {
|
||||
FeatureMeta,
|
||||
FeatureFilters,
|
||||
|
|
@ -107,6 +108,7 @@ export function useHexagonSelection({ filters, features, resolution }: UseHexago
|
|||
setSelectedPostcodeGeometry(null);
|
||||
} else {
|
||||
const type = isPostcode ? 'postcode' : 'hexagon';
|
||||
trackEvent('Hexagon Click', { type });
|
||||
setSelectedHexagon({ id, type, resolution });
|
||||
setSelectedPostcodeGeometry(isPostcode && geometry ? geometry : null);
|
||||
setProperties([]);
|
||||
|
|
@ -138,6 +140,7 @@ export function useHexagonSelection({ filters, features, resolution }: UseHexago
|
|||
|
||||
const handleViewPropertiesFromArea = useCallback(() => {
|
||||
if (selectedHexagon && selectedHexagon.type === 'hexagon') {
|
||||
trackEvent('View Properties');
|
||||
setRightPaneTab('properties');
|
||||
setPropertiesOffset(0);
|
||||
fetchHexagonProperties(selectedHexagon.id, selectedHexagon.resolution, 0);
|
||||
|
|
@ -167,6 +170,7 @@ export function useHexagonSelection({ filters, features, resolution }: UseHexago
|
|||
|
||||
const handleLocationSearch = useCallback(
|
||||
(postcode: string, geometry: PostcodeGeometry) => {
|
||||
trackEvent('Postcode Search');
|
||||
setSelectedHexagon({ id: postcode, type: 'postcode', resolution });
|
||||
setSelectedPostcodeGeometry(geometry);
|
||||
setProperties([]);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import { useState, useCallback } from 'react';
|
||||
import { apiUrl, authHeaders, assertOk } from '../lib/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
|
||||
export function useLicense() {
|
||||
const [checkingOut, setCheckingOut] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const startCheckout = useCallback(async (referralCode?: string) => {
|
||||
trackEvent('Checkout Start', { has_referral: String(!!referralCode) });
|
||||
setCheckingOut(true);
|
||||
setError(null);
|
||||
try {
|
||||
|
|
@ -22,6 +24,7 @@ export function useLicense() {
|
|||
assertOk(res, 'Checkout');
|
||||
const data = await res.json();
|
||||
if (data.url) {
|
||||
trackEvent('Checkout Redirect');
|
||||
window.location.href = data.url;
|
||||
}
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -7,5 +7,6 @@ plausibleInit({
|
|||
captureOnLocalhost: true,
|
||||
logging: true,
|
||||
fileDownloads: true,
|
||||
outboundLinks: true,
|
||||
hashBasedRouting: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { useState, useCallback } from 'react';
|
||||
import pb from '../lib/pocketbase';
|
||||
import { apiUrl, authHeaders } from '../lib/api';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
|
||||
export interface SavedSearch {
|
||||
id: string;
|
||||
|
|
@ -66,6 +67,7 @@ export function useSavedSearches(userId: string | null) {
|
|||
formData.append('screenshot', screenshotBlob, 'screenshot.png');
|
||||
|
||||
await pb.collection('saved_searches').create(formData);
|
||||
trackEvent('Search Save');
|
||||
await fetchSearches();
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : 'Failed to save search';
|
||||
|
|
@ -82,6 +84,7 @@ export function useSavedSearches(userId: string | null) {
|
|||
setError(null);
|
||||
try {
|
||||
await pb.collection('saved_searches').delete(id);
|
||||
trackEvent('Search Delete');
|
||||
setSearches((prev) => prev.filter((s) => s.id !== id));
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to delete search');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue