diff --git a/src/frontend/apps/impress/src/features/auth/hooks/__tests__/useAuth.test.tsx b/src/frontend/apps/impress/src/features/auth/hooks/__tests__/useAuth.test.tsx
new file mode 100644
index 00000000..56c56df3
--- /dev/null
+++ b/src/frontend/apps/impress/src/features/auth/hooks/__tests__/useAuth.test.tsx
@@ -0,0 +1,81 @@
+import { renderHook, waitFor } from '@testing-library/react';
+import fetchMock from 'fetch-mock';
+import { Fragment } from 'react';
+
+import { AbstractAnalytic } from '@/libs';
+import { AppWrapper } from '@/tests/utils';
+
+import { useAuth } from '../useAuth';
+
+const trackEventMock = jest.fn();
+const flag = true;
+class TestAnalytic extends AbstractAnalytic {
+ public constructor() {
+ super();
+ }
+
+ public Provider() {
+ return ;
+ }
+
+ public trackEvent(props: any) {
+ trackEventMock(props);
+ }
+
+ public isFeatureFlagActivated(flagName: string): boolean {
+ if (flagName === 'CopyAsHTML') {
+ return flag;
+ }
+
+ return true;
+ }
+}
+
+jest.mock('next/router', () => ({
+ ...jest.requireActual('next/router'),
+ useRouter: () => ({
+ pathname: '/dashboard',
+ replace: jest.fn(),
+ }),
+}));
+
+const dummyUser = { id: '123', email: 'test@example.com' };
+
+describe('useAuth hook - trackEvent effect', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ fetchMock.restore();
+ });
+
+ test('calls trackEvent when user exists, isSuccess is true, and event was not tracked yet', async () => {
+ new TestAnalytic();
+
+ fetchMock.get('http://test.jest/api/v1.0/users/me/', {
+ body: JSON.stringify(dummyUser),
+ });
+
+ renderHook(() => useAuth(), {
+ wrapper: AppWrapper,
+ });
+
+ await waitFor(() => {
+ expect(trackEventMock).toHaveBeenCalledWith({
+ eventName: 'user',
+ id: dummyUser.id,
+ email: dummyUser.email,
+ });
+ });
+ });
+
+ test('does not call trackEvent if already tracked', () => {
+ fetchMock.get('http://test.jest/api/v1.0/users/me/', {
+ body: JSON.stringify(dummyUser),
+ });
+
+ renderHook(() => useAuth(), {
+ wrapper: AppWrapper,
+ });
+
+ expect(trackEventMock).not.toHaveBeenCalled();
+ });
+});
diff --git a/src/frontend/apps/impress/src/features/auth/hooks/useAuth.tsx b/src/frontend/apps/impress/src/features/auth/hooks/useAuth.tsx
index 92fa8f15..dc9054da 100644
--- a/src/frontend/apps/impress/src/features/auth/hooks/useAuth.tsx
+++ b/src/frontend/apps/impress/src/features/auth/hooks/useAuth.tsx
@@ -1,6 +1,8 @@
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
+import { useAnalytics } from '@/libs';
+
import { useAuthQuery } from '../api';
const regexpUrlsAuth = [/\/docs\/$/g, /\/docs$/g, /^\/$/g];
@@ -8,7 +10,8 @@ const regexpUrlsAuth = [/\/docs\/$/g, /\/docs$/g, /^\/$/g];
export const useAuth = () => {
const { data: user, ...authStates } = useAuthQuery();
const { pathname } = useRouter();
-
+ const { trackEvent } = useAnalytics();
+ const [hasTracked, setHasTracked] = useState(authStates.isFetched);
const [pathAllowed, setPathAllowed] = useState(
!regexpUrlsAuth.some((regexp) => !!pathname.match(regexp)),
);
@@ -17,6 +20,17 @@ export const useAuth = () => {
setPathAllowed(!regexpUrlsAuth.some((regexp) => !!pathname.match(regexp)));
}, [pathname]);
+ useEffect(() => {
+ if (!hasTracked && user && authStates.isSuccess) {
+ trackEvent({
+ eventName: 'user',
+ id: user?.id || '',
+ email: user?.email || '',
+ });
+ setHasTracked(true);
+ }
+ }, [hasTracked, authStates.isSuccess, user, trackEvent]);
+
return {
user,
authenticated: !!user && authStates.isSuccess,
diff --git a/src/frontend/apps/impress/src/services/PosthogAnalytic.tsx b/src/frontend/apps/impress/src/services/PosthogAnalytic.tsx
index deaf0b71..4b44cf29 100644
--- a/src/frontend/apps/impress/src/services/PosthogAnalytic.tsx
+++ b/src/frontend/apps/impress/src/services/PosthogAnalytic.tsx
@@ -3,7 +3,7 @@ import posthog from 'posthog-js';
import { PostHogProvider as PHProvider } from 'posthog-js/react';
import { JSX, PropsWithChildren, ReactNode, useEffect } from 'react';
-import { AbstractAnalytic } from '@/libs/';
+import { AbstractAnalytic, AnalyticEvent } from '@/libs/';
export class PostHogAnalytic extends AbstractAnalytic {
private conf?: PostHogConf = undefined;
@@ -18,7 +18,11 @@ export class PostHogAnalytic extends AbstractAnalytic {
return {children};
}
- public trackEvent(): void {}
+ public trackEvent(evt: AnalyticEvent): void {
+ if (evt.eventName === 'user') {
+ posthog.identify(evt.id, { email: evt.email });
+ }
+ }
public isFeatureFlagActivated(flagName: string): boolean {
if (