mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-04 12:13:27 +00:00
Mobile Analytics and some changes (#667)
* update contributing & environment-setup * fix pods deployment target to 13.0 * Track app screen changes with plausible * Don't track onboarding * remove platformType from usePlausibleEvent * submit custom plausible events
This commit is contained in:
parent
86c47dde4a
commit
63afacbc54
|
@ -61,7 +61,7 @@ To run the landing page:
|
|||
|
||||
If you are having issues ensure you are using the following versions of Rust and Node:
|
||||
|
||||
- Rust version: **1.67.0**
|
||||
- Rust version: **1.68.2**
|
||||
- Node version: **18**
|
||||
|
||||
Be sure to read the [guidelines](https://spacedrive.com/docs/developers/prerequisites/guidelines) to make sure your code is a similar style to ours.
|
||||
|
|
|
@ -74,6 +74,8 @@ target 'Spacedrive' do
|
|||
target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
|
||||
resource_bundle_target.build_configurations.each do |config|
|
||||
config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
|
||||
# Spacedrive - Added to fix the issue with the deployment target
|
||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = podfile_properties['ios.deploymentTarget'] || '13.0'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
|
||||
import { DefaultTheme, NavigationContainer, Theme } from '@react-navigation/native';
|
||||
import {
|
||||
DefaultTheme,
|
||||
NavigationContainer,
|
||||
Theme,
|
||||
useNavigationContainerRef
|
||||
} from '@react-navigation/native';
|
||||
import { loggerLink } from '@rspc/client';
|
||||
import { QueryClient } from '@tanstack/react-query';
|
||||
import dayjs from 'dayjs';
|
||||
|
@ -8,19 +13,21 @@ import duration from 'dayjs/plugin/duration';
|
|||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import * as SplashScreen from 'expo-splash-screen';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
||||
import { MenuProvider } from 'react-native-popup-menu';
|
||||
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
import { useDeviceContext } from 'twrnc';
|
||||
import { proxy, useSnapshot } from 'valtio';
|
||||
import { useSnapshot } from 'valtio';
|
||||
import {
|
||||
ClientContextProvider,
|
||||
LibraryContextProvider,
|
||||
getDebugState,
|
||||
initPlausible,
|
||||
rspc,
|
||||
useClientContext,
|
||||
useInvalidateQuery
|
||||
useInvalidateQuery,
|
||||
usePlausiblePageViewMonitor
|
||||
} from '@sd/client';
|
||||
import { GlobalModals } from './components/modal/GlobalModals';
|
||||
import { reactNativeLink } from './lib/rspcReactNativeTransport';
|
||||
|
@ -42,14 +49,43 @@ const NavigatorTheme: Theme = {
|
|||
}
|
||||
};
|
||||
|
||||
initPlausible({ platformType: 'mobile' });
|
||||
|
||||
function AppNavigation() {
|
||||
const { library } = useClientContext();
|
||||
|
||||
// TODO: Make sure library has actually been loaded by this point - precache with useCachedLibraries?
|
||||
// if (library === undefined) throw new Error("Tried to render AppNavigation before libraries fetched!")
|
||||
|
||||
const navRef = useNavigationContainerRef();
|
||||
const routeNameRef = useRef<string>();
|
||||
|
||||
const [currentPath, setCurrentPath] = useState<string>('/');
|
||||
|
||||
usePlausiblePageViewMonitor({ currentPath });
|
||||
|
||||
return (
|
||||
<NavigationContainer theme={NavigatorTheme}>
|
||||
<NavigationContainer
|
||||
ref={navRef}
|
||||
onReady={() => {
|
||||
routeNameRef.current = navRef.getCurrentRoute()?.name;
|
||||
}}
|
||||
theme={NavigatorTheme}
|
||||
onStateChange={async () => {
|
||||
const previousRouteName = routeNameRef.current;
|
||||
const currentRouteName = navRef.getCurrentRoute()?.name;
|
||||
if (previousRouteName !== currentRouteName) {
|
||||
// Save the current route name for later comparison
|
||||
routeNameRef.current = currentRouteName;
|
||||
// Don't track onboarding screens
|
||||
if (navRef.getRootState().routeNames.includes('GetStarted')) {
|
||||
return;
|
||||
}
|
||||
console.log(`Navigated from ${previousRouteName} to ${currentRouteName}`);
|
||||
currentRouteName && setCurrentPath(currentRouteName);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{!library ? (
|
||||
<OnboardingNavigator />
|
||||
) : (
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useState } from 'react';
|
||||
import { useBridgeMutation } from '@sd/client';
|
||||
import { useBridgeMutation, usePlausibleEvent } from '@sd/client';
|
||||
import { Input } from '~/components/form/Input';
|
||||
import Dialog from '~/components/layout/Dialog';
|
||||
import { currentLibraryStore } from '~/utils/nav';
|
||||
|
@ -17,6 +17,8 @@ const CreateLibraryDialog = ({ children, onSubmit, disableBackdropClose }: Props
|
|||
const [libName, setLibName] = useState('');
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const { mutate: createLibrary, isLoading: createLibLoading } = useBridgeMutation(
|
||||
'library.create',
|
||||
{
|
||||
|
@ -30,6 +32,8 @@ const CreateLibraryDialog = ({ children, onSubmit, disableBackdropClose }: Props
|
|||
// Switch to the new library
|
||||
currentLibraryStore.id = lib.uuid;
|
||||
|
||||
submitPlausibleEvent({ event: { type: 'libraryCreate' } });
|
||||
|
||||
onSubmit?.();
|
||||
},
|
||||
onSettled: () => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useRef } from 'react';
|
||||
import { useBridgeMutation } from '@sd/client';
|
||||
import { useBridgeMutation, usePlausibleEvent } from '@sd/client';
|
||||
import { ConfirmModal, ModalRef } from '~/components/layout/Modal';
|
||||
|
||||
type Props = {
|
||||
|
@ -13,12 +13,19 @@ const DeleteLibraryModal = ({ trigger, onSubmit, libraryUuid }: Props) => {
|
|||
const queryClient = useQueryClient();
|
||||
const modalRef = useRef<ModalRef>(null);
|
||||
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const { mutate: deleteLibrary, isLoading: deleteLibLoading } = useBridgeMutation(
|
||||
'library.delete',
|
||||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(['library.list']);
|
||||
onSubmit?.();
|
||||
submitPlausibleEvent({
|
||||
event: {
|
||||
type: 'libraryDelete'
|
||||
}
|
||||
});
|
||||
},
|
||||
onSettled: () => {
|
||||
modalRef.current?.close();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useRef } from 'react';
|
||||
import { useLibraryMutation } from '@sd/client';
|
||||
import { useLibraryMutation, usePlausibleEvent } from '@sd/client';
|
||||
import { ConfirmModal, ModalRef } from '~/components/layout/Modal';
|
||||
|
||||
type Props = {
|
||||
|
@ -11,10 +11,13 @@ type Props = {
|
|||
const DeleteLocationModal = ({ trigger, onSubmit, locationId }: Props) => {
|
||||
const modalRef = useRef<ModalRef>(null);
|
||||
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const { mutate: deleteLoc, isLoading: deleteLocLoading } = useLibraryMutation(
|
||||
'locations.delete',
|
||||
{
|
||||
onSuccess: () => {
|
||||
submitPlausibleEvent({ event: { type: 'locationDelete' } });
|
||||
onSubmit?.();
|
||||
},
|
||||
onSettled: () => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { useRef } from 'react';
|
||||
import { useLibraryMutation } from '@sd/client';
|
||||
import { useLibraryMutation, usePlausibleEvent } from '@sd/client';
|
||||
import { ConfirmModal, ModalRef } from '~/components/layout/Modal';
|
||||
|
||||
type Props = {
|
||||
|
@ -11,8 +11,11 @@ type Props = {
|
|||
const DeleteTagModal = ({ trigger, onSubmit, tagId }: Props) => {
|
||||
const modalRef = useRef<ModalRef>(null);
|
||||
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const { mutate: deleteTag, isLoading: deleteTagLoading } = useLibraryMutation('tags.delete', {
|
||||
onSuccess: () => {
|
||||
submitPlausibleEvent({ event: { type: 'tagDelete' } });
|
||||
onSubmit?.();
|
||||
},
|
||||
onSettled: () => {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { useQueryClient } from '@tanstack/react-query';
|
|||
import { forwardRef, useEffect, useState } from 'react';
|
||||
import { Pressable, Text, View } from 'react-native';
|
||||
import ColorPicker from 'react-native-wheel-color-picker';
|
||||
import { useLibraryMutation } from '@sd/client';
|
||||
import { useLibraryMutation, usePlausibleEvent } from '@sd/client';
|
||||
import { FadeInAnimation } from '~/components/animation/layout';
|
||||
import { Input } from '~/components/form/Input';
|
||||
import { Modal, ModalRef } from '~/components/layout/Modal';
|
||||
|
@ -20,6 +20,8 @@ const CreateTagModal = forwardRef<ModalRef, unknown>((_, ref) => {
|
|||
|
||||
// TODO: Use react-hook-form?
|
||||
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const { mutate: createTag } = useLibraryMutation('tags.create', {
|
||||
onSuccess: () => {
|
||||
// Reset form
|
||||
|
@ -28,6 +30,8 @@ const CreateTagModal = forwardRef<ModalRef, unknown>((_, ref) => {
|
|||
setShowPicker(false);
|
||||
|
||||
queryClient.invalidateQueries(['tags.list']);
|
||||
|
||||
submitPlausibleEvent({ event: { type: 'tagCreate' } });
|
||||
},
|
||||
onSettled: () => {
|
||||
// Close modal
|
||||
|
|
|
@ -12,6 +12,7 @@ const Drawer = createDrawerNavigator<DrawerNavParamList>();
|
|||
export default function DrawerNavigator() {
|
||||
return (
|
||||
<Drawer.Navigator
|
||||
id="drawer"
|
||||
initialRouteName="Home"
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
|
|
|
@ -9,7 +9,11 @@ const OnboardingStack = createStackNavigator<OnboardingStackParamList>();
|
|||
|
||||
export default function OnboardingNavigator() {
|
||||
return (
|
||||
<OnboardingStack.Navigator initialRouteName="GetStarted" screenOptions={{ headerShown: false }}>
|
||||
<OnboardingStack.Navigator
|
||||
id="onboarding"
|
||||
initialRouteName="GetStarted"
|
||||
screenOptions={{ headerShown: false }}
|
||||
>
|
||||
<OnboardingStack.Screen name="GetStarted" component={GetStartedScreen} />
|
||||
<OnboardingStack.Screen name="NewLibrary" component={NewLibraryScreen} />
|
||||
<OnboardingStack.Screen name="MasterPassword" component={MasterPasswordScreen} />
|
||||
|
|
|
@ -20,6 +20,7 @@ const SettingsStack = createStackNavigator<SettingsStackParamList>();
|
|||
export default function SettingsNavigator() {
|
||||
return (
|
||||
<SettingsStack.Navigator
|
||||
id="settings"
|
||||
initialRouteName="Home"
|
||||
screenOptions={{
|
||||
headerBackTitleVisible: false,
|
||||
|
|
|
@ -13,6 +13,7 @@ const Tab = createBottomTabNavigator<TabParamList>();
|
|||
export default function TabNavigator() {
|
||||
return (
|
||||
<Tab.Navigator
|
||||
id="tab"
|
||||
initialRouteName="OverviewStack"
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
|
|
|
@ -7,7 +7,8 @@ import {
|
|||
telemetryStore,
|
||||
useBridgeMutation,
|
||||
useDebugState,
|
||||
useOnboardingStore
|
||||
useOnboardingStore,
|
||||
usePlausibleEvent
|
||||
} from '@sd/client';
|
||||
import { PulseAnimation } from '~/components/animation/lottie';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
|
@ -23,12 +24,17 @@ const CreatingLibraryScreen = ({ navigation }: OnboardingStackScreenProps<'Creat
|
|||
const debugState = useDebugState();
|
||||
const obStore = useOnboardingStore();
|
||||
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const createLibrary = useBridgeMutation('library.create', {
|
||||
onSuccess: (lib) => {
|
||||
resetOnboardingStore();
|
||||
queryClient.setQueryData(['library.list'], (libraries: any) => [...(libraries || []), lib]);
|
||||
// Switch to the new library
|
||||
currentLibraryStore.id = lib.uuid;
|
||||
if (obStore.shareTelemetry) {
|
||||
submitPlausibleEvent({ event: { type: 'libraryCreate' } });
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
// TODO: Show toast
|
||||
|
|
|
@ -67,5 +67,5 @@ To run mobile app
|
|||
|
||||
If you are having issues ensure you are using the following versions of Rust and Node:
|
||||
|
||||
- Rust version: **1.67.0**
|
||||
- Rust version: **1.68.2**
|
||||
- Node version: **18**
|
||||
|
|
|
@ -5,12 +5,10 @@ import { useRef } from 'react';
|
|||
import { useLibraryMutation, useLibraryQuery, usePlausibleEvent } from '@sd/client';
|
||||
import { ContextMenu, DropdownMenu, dialogManager, useContextMenu, useDropdownMenu } from '@sd/ui';
|
||||
import { useScrolled } from '~/hooks/useScrolled';
|
||||
import { usePlatform } from '~/util/Platform';
|
||||
import CreateDialog from '../settings/library/tags/CreateDialog';
|
||||
|
||||
export default (props: { objectId: number }) => {
|
||||
const platform = usePlatform();
|
||||
const submitPlausibleEvent = usePlausibleEvent({ platformType: platform.platform });
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const tags = useLibraryQuery(['tags.list'], { suspense: true });
|
||||
const tagsForObject = useLibraryQuery(['tags.getForObject', props.objectId], { suspense: true });
|
||||
|
|
|
@ -4,6 +4,7 @@ import { Navigate, Outlet, useLocation, useParams } from 'react-router-dom';
|
|||
import {
|
||||
ClientContextProvider,
|
||||
LibraryContextProvider,
|
||||
initPlausible,
|
||||
useClientContext,
|
||||
usePlausiblePageViewMonitor
|
||||
} from '@sd/client';
|
||||
|
@ -17,10 +18,10 @@ const Layout = () => {
|
|||
|
||||
const os = useOperatingSystem();
|
||||
|
||||
usePlausiblePageViewMonitor({
|
||||
currentPath: useLocation().pathname,
|
||||
platformType: usePlatform().platform
|
||||
initPlausible({
|
||||
platformType: usePlatform().platform === 'tauri' ? 'desktop' : 'web'
|
||||
});
|
||||
usePlausiblePageViewMonitor({ currentPath: useLocation().pathname });
|
||||
|
||||
if (library === null && libraries.data) {
|
||||
const firstLibrary = libraries.data[0];
|
||||
|
@ -33,10 +34,10 @@ const Layout = () => {
|
|||
<div
|
||||
className={clsx(
|
||||
// App level styles
|
||||
'text-ink flex h-screen cursor-default select-none overflow-hidden',
|
||||
os === 'browser' && 'bg-app border-app-line/50 border-t',
|
||||
'flex h-screen cursor-default select-none overflow-hidden text-ink',
|
||||
os === 'browser' && 'border-t border-app-line/50 bg-app',
|
||||
os === 'macOS' && 'has-blur-effects rounded-[10px]',
|
||||
os !== 'browser' && os !== 'windows' && 'border-app-frame border'
|
||||
os !== 'browser' && os !== 'windows' && 'border border-app-frame'
|
||||
)}
|
||||
onContextMenu={(e) => {
|
||||
// TODO: allow this on some UI text at least / disable default browser context menu
|
||||
|
@ -48,7 +49,7 @@ const Layout = () => {
|
|||
<div className="relative flex w-full">
|
||||
{library ? (
|
||||
<LibraryContextProvider library={library}>
|
||||
<Suspense fallback={<div className="bg-app h-screen w-screen" />}>
|
||||
<Suspense fallback={<div className="h-screen w-screen bg-app" />}>
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
</LibraryContextProvider>
|
||||
|
|
|
@ -10,8 +10,7 @@ interface Props extends UseDialogProps {
|
|||
|
||||
export default (props: Props) => {
|
||||
const dialog = useDialog(props);
|
||||
const platform = usePlatform();
|
||||
const submitPlausibleEvent = usePlausibleEvent({ platformType: platform.platform });
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const form = useZodForm();
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@ import { usePlatform } from '~/util/Platform';
|
|||
|
||||
export default (props: UseDialogProps & { assignToObject?: number }) => {
|
||||
const dialog = useDialog(props);
|
||||
const platform = usePlatform();
|
||||
const submitPlausibleEvent = usePlausibleEvent({ platformType: platform.platform });
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const form = useZodForm({
|
||||
schema: z.object({
|
||||
|
|
|
@ -10,8 +10,7 @@ interface Props extends UseDialogProps {
|
|||
|
||||
export default (props: Props) => {
|
||||
const dialog = useDialog(props);
|
||||
const platform = usePlatform();
|
||||
const submitPlausibleEvent = usePlausibleEvent({ platformType: platform.platform });
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const form = useZodForm();
|
||||
|
||||
|
|
|
@ -17,12 +17,11 @@ import {
|
|||
SelectOption,
|
||||
Tooltip,
|
||||
UseDialogProps,
|
||||
forms,
|
||||
useDialog
|
||||
} from '@sd/ui';
|
||||
import { forms } from '@sd/ui';
|
||||
import { PasswordMeter } from '~/components/PasswordMeter';
|
||||
import { generatePassword } from '~/util';
|
||||
import { usePlatform } from '~/util/Platform';
|
||||
|
||||
const { Input, z, useZodForm } = forms;
|
||||
|
||||
|
@ -37,8 +36,7 @@ const schema = z.object({
|
|||
|
||||
export default (props: UseDialogProps) => {
|
||||
const dialog = useDialog(props);
|
||||
const platform = usePlatform();
|
||||
const createLibraryEvent = usePlausibleEvent({ platformType: platform.platform });
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const form = useZodForm({
|
||||
schema,
|
||||
|
@ -62,7 +60,7 @@ export default (props: UseDialogProps) => {
|
|||
library
|
||||
]);
|
||||
|
||||
createLibraryEvent({
|
||||
submitPlausibleEvent({
|
||||
event: {
|
||||
type: 'libraryCreate'
|
||||
}
|
||||
|
@ -116,7 +114,7 @@ export default (props: UseDialogProps) => {
|
|||
</div>
|
||||
<span className="mt-1 text-xs font-medium">Share anonymous usage</span>
|
||||
<Tooltip label="Share completely anonymous telemetry data to help the developers improve the app">
|
||||
<Info className="text-ink-faint ml-1.5 h-4 w-4" />
|
||||
<Info className="ml-1.5 h-4 w-4 text-ink-faint" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -12,9 +12,7 @@ interface Props extends UseDialogProps {
|
|||
|
||||
export default function DeleteLibraryDialog(props: Props) {
|
||||
const dialog = useDialog(props);
|
||||
const platform = usePlatform();
|
||||
const submitPlausibleEvent = usePlausibleEvent({ platformType: platform.platform });
|
||||
const shareTelemetry = useTelemetryState().shareTelemetry;
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const deleteLib = useBridgeMutation('library.delete', {
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
usePlausibleEvent
|
||||
} from '@sd/client';
|
||||
import { Loader } from '@sd/ui';
|
||||
import { usePlatform } from '~/util/Platform';
|
||||
import { OnboardingContainer, OnboardingDescription, OnboardingTitle } from './Layout';
|
||||
import { useUnlockOnboardingScreen } from './Progress';
|
||||
|
||||
|
@ -19,8 +18,7 @@ export default function OnboardingCreatingLibrary() {
|
|||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
const debugState = useDebugState();
|
||||
const platform = usePlatform();
|
||||
const submitPlausibleEvent = usePlausibleEvent({ platformType: platform.platform });
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const [status, setStatus] = useState('Creating your library...');
|
||||
|
||||
|
@ -33,7 +31,9 @@ export default function OnboardingCreatingLibrary() {
|
|||
library
|
||||
]);
|
||||
|
||||
submitPlausibleEvent({ event: { type: 'libraryCreate' } });
|
||||
if (obStore.shareTelemetry) {
|
||||
submitPlausibleEvent({ event: { type: 'libraryCreate' } });
|
||||
}
|
||||
|
||||
resetOnboardingStore();
|
||||
navigate(`/${library.uuid}/overview`);
|
||||
|
|
|
@ -1,26 +1,16 @@
|
|||
import Plausible from 'plausible-tracker';
|
||||
import { PlausibleOptions as PlausibleTrackerOptions } from 'plausible-tracker';
|
||||
import Plausible, { PlausibleOptions as PlausibleTrackerOptions } from 'plausible-tracker';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useDebugState, useTelemetryState } from '../stores';
|
||||
import { PlausiblePlatformType, telemetryStore, useDebugState, useTelemetryState } from '../stores';
|
||||
|
||||
/**
|
||||
* This should be in sync with the Core's version.
|
||||
*/
|
||||
const Version = '0.1.0';
|
||||
|
||||
/**
|
||||
* Possible Platform types that can be sourced from `usePlatform().platform` or even hardcoded.
|
||||
*
|
||||
* @remarks
|
||||
* The `tauri` platform is renamed to `desktop` for analytic purposes.
|
||||
*/
|
||||
type PlatformType = 'web' | 'mobile' | 'tauri';
|
||||
|
||||
const Domain = 'app.spacedrive.com';
|
||||
const VERSION = '0.1.0';
|
||||
const DOMAIN = 'app.spacedrive.com';
|
||||
|
||||
const PlausibleProvider = Plausible({
|
||||
trackLocalhost: true,
|
||||
domain: Domain
|
||||
domain: DOMAIN
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -71,7 +61,7 @@ type PageViewEvent = BasePlausibleEvent<'pageview', 'url'>;
|
|||
* @example
|
||||
* ```ts
|
||||
* const platform = usePlatform();
|
||||
* const submitPlausibleEvent = usePlausibleEvent({ platformType: platform.platform });
|
||||
* const submitPlausibleEvent = usePlausibleEvent();
|
||||
*
|
||||
* const createLibrary = useBridgeMutation('library.create', {
|
||||
* onSuccess: (library) => {
|
||||
|
@ -97,7 +87,7 @@ type TagAssignEvent = BasePlausibleEvent<'tagAssign'>;
|
|||
/**
|
||||
* All union of available, ready-to-use events.
|
||||
*
|
||||
* Every possible event must also be added as a "goal" in Plausible's settings (on their site) for the currently active {@link Domain domain}.
|
||||
* Every possible event must also be added as a "goal" in Plausible's settings (on their site) for the currently active {@link DOMAIN domain}.
|
||||
*/
|
||||
type PlausibleEvent =
|
||||
| PageViewEvent
|
||||
|
@ -117,7 +107,7 @@ type PlausibleEvent =
|
|||
interface PlausibleTrackerEvent {
|
||||
eventName: string;
|
||||
props: {
|
||||
platform: 'web' | 'desktop' | 'mobile';
|
||||
platform: PlausiblePlatformType;
|
||||
version: string;
|
||||
debug: boolean;
|
||||
};
|
||||
|
@ -135,9 +125,9 @@ interface SubmitEventProps {
|
|||
/**
|
||||
* The current platform type. This should be the output of `usePlatform().platform`
|
||||
*
|
||||
* @see {@link PlatformType}
|
||||
* @see {@link PlausiblePlatformType}
|
||||
*/
|
||||
platformType: PlatformType;
|
||||
platformType: PlausiblePlatformType;
|
||||
/**
|
||||
* An optional screen width. Default is `window.screen.width`
|
||||
*/
|
||||
|
@ -182,6 +172,7 @@ interface SubmitEventProps {
|
|||
* @see {@link https://plausible-tracker.netlify.app/#tracking-custom-events-and-goals Tracking custom events}
|
||||
*/
|
||||
const submitPlausibleEvent = async ({ event, debugState, ...props }: SubmitEventProps) => {
|
||||
if (props.platformType === 'unknown') return;
|
||||
if (debugState.enabled && debugState.shareTelemetry !== true) return;
|
||||
if (
|
||||
'plausibleOptions' in event && 'telemetryOverride' in event.plausibleOptions
|
||||
|
@ -193,8 +184,8 @@ const submitPlausibleEvent = async ({ event, debugState, ...props }: SubmitEvent
|
|||
const fullEvent: PlausibleTrackerEvent = {
|
||||
eventName: event.type,
|
||||
props: {
|
||||
platform: props.platformType === 'tauri' ? 'desktop' : props.platformType,
|
||||
version: Version,
|
||||
platform: props.platformType,
|
||||
version: VERSION,
|
||||
debug: debugState.enabled
|
||||
},
|
||||
options: {
|
||||
|
@ -224,9 +215,9 @@ interface UsePlausibleEventProps {
|
|||
/**
|
||||
* The current platform type. This should be the output of `usePlatform().platform`
|
||||
*
|
||||
* @see {@link PlatformType}
|
||||
* @see {@link PlausiblePlatformType}
|
||||
*/
|
||||
platformType: PlatformType;
|
||||
platformType: PlausiblePlatformType;
|
||||
}
|
||||
|
||||
interface EventSubmissionCallbackProps {
|
||||
|
@ -260,7 +251,7 @@ interface EventSubmissionCallbackProps {
|
|||
* @example
|
||||
* ```ts
|
||||
* const platform = usePlatform();
|
||||
* const submitPlausibleEvent = usePlausibleEvent({ platformType: platform.platform });
|
||||
* const submitPlausibleEvent = usePlausibleEvent();
|
||||
*
|
||||
* const createLibrary = useBridgeMutation('library.create', {
|
||||
* onSuccess: (library) => {
|
||||
|
@ -273,9 +264,9 @@ interface EventSubmissionCallbackProps {
|
|||
* });
|
||||
* ```
|
||||
*/
|
||||
export const usePlausibleEvent = ({ platformType }: UsePlausibleEventProps) => {
|
||||
export const usePlausibleEvent = () => {
|
||||
const debugState = useDebugState();
|
||||
const shareTelemetry = useTelemetryState().shareTelemetry;
|
||||
const telemetryState = useTelemetryState();
|
||||
const previousEvent = useRef({} as BasePlausibleEvent<string>);
|
||||
|
||||
return useCallback(
|
||||
|
@ -283,9 +274,14 @@ export const usePlausibleEvent = ({ platformType }: UsePlausibleEventProps) => {
|
|||
if (previousEvent.current === props.event) return;
|
||||
else previousEvent.current = props.event;
|
||||
|
||||
submitPlausibleEvent({ debugState, shareTelemetry, platformType, ...props });
|
||||
submitPlausibleEvent({
|
||||
debugState,
|
||||
shareTelemetry: telemetryState.shareTelemetry,
|
||||
platformType: telemetryState.platform,
|
||||
...props
|
||||
});
|
||||
},
|
||||
[debugState, platformType, shareTelemetry]
|
||||
[debugState, telemetryState]
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -331,12 +327,6 @@ export interface PageViewMonitorProps {
|
|||
* @see {@link PageViewRegexRules} for sanitization
|
||||
*/
|
||||
currentPath: string;
|
||||
/**
|
||||
* The current platform type. This should be the output of `usePlatform().platform`
|
||||
*
|
||||
* @see {@link PlatformType}
|
||||
*/
|
||||
platformType: PlatformType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -358,15 +348,14 @@ export interface PageViewMonitorProps {
|
|||
* @example
|
||||
* ```ts
|
||||
* usePlausiblePageViewMonitor({
|
||||
* currentPath: useLocation().pathname,
|
||||
* platformType: usePlatform().platform
|
||||
* currentPath: useLocation().pathname
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export const usePlausiblePageViewMonitor = (props: PageViewMonitorProps) => {
|
||||
const plausibleEvent = usePlausibleEvent({ platformType: props.platformType });
|
||||
export const usePlausiblePageViewMonitor = ({ currentPath }: PageViewMonitorProps) => {
|
||||
const plausibleEvent = usePlausibleEvent();
|
||||
|
||||
let path = props.currentPath;
|
||||
let path = currentPath;
|
||||
PageViewRegexRules.forEach((e) => (path = path.replace(e[0], e[1])));
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -378,3 +367,8 @@ export const usePlausiblePageViewMonitor = (props: PageViewMonitorProps) => {
|
|||
});
|
||||
}, [path, plausibleEvent]);
|
||||
};
|
||||
|
||||
export const initPlausible = ({ platformType }: { platformType: PlausiblePlatformType }) => {
|
||||
telemetryStore.platform = platformType;
|
||||
return;
|
||||
};
|
||||
|
|
|
@ -1,8 +1,22 @@
|
|||
import { useSnapshot } from 'valtio';
|
||||
import { valtioPersist } from './util';
|
||||
|
||||
export const telemetryStore = valtioPersist('sd-telemetryStore', {
|
||||
shareTelemetry: false // false by default, so functions cannot accidentally send data if the user has not decided
|
||||
/**
|
||||
* Possible Platform types that can be sourced from `usePlatform().platform` or even hardcoded.
|
||||
*
|
||||
* @remarks
|
||||
* The `tauri` platform is renamed to `desktop` for analytic purposes.
|
||||
*/
|
||||
export type PlausiblePlatformType = 'web' | 'mobile' | 'desktop' | 'unknown';
|
||||
|
||||
type TelemetryState = {
|
||||
shareTelemetry: boolean;
|
||||
platform: PlausiblePlatformType;
|
||||
};
|
||||
|
||||
export const telemetryStore = valtioPersist<TelemetryState>('sd-telemetryStore', {
|
||||
shareTelemetry: false, // false by default, so functions cannot accidentally send data if the user has not decided
|
||||
platform: 'unknown'
|
||||
});
|
||||
|
||||
export function useTelemetryState() {
|
||||
|
|
Loading…
Reference in a new issue