Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Amplitude 사용자 트래킹 코드 고도화 #979

Open
wants to merge 17 commits into
base: fe-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
3938776
refactor: @amplitude/analytics-browser에서 필요한 모듈만 사용하는 방식으로 변경
jinhokim98 Jan 27, 2025
0224d45
style: 함수명 오타 수정
jinhokim98 Jan 27, 2025
89e85d6
feat: auth store에 카카오 유저 여부도 추가
jinhokim98 Jan 27, 2025
edf6f4d
fix: 회원 행사 생성 완료 시 trackCompleteCreateEvent이벤트로 변경 (상위에서 이미 카카오 유저 판단…
jinhokim98 Jan 27, 2025
9c7c9bd
feat: Amplitude 트래킹 코드 추가 정의
jinhokim98 Jan 27, 2025
0446fe8
feat: 랜딩 페이지 최하단을 확인하는지를 체크하는 track 코드 적용
jinhokim98 Jan 27, 2025
fe8ea31
feat: 전체 지출 내역 탭을 클릭했을 때 트래킹 코드 실행
jinhokim98 Jan 27, 2025
26e58a2
feat: 전체 사용자 이름 변경 수와 입금상태 변경 수를 트래킹하는 기능 구현
jinhokim98 Jan 27, 2025
47b8c39
feat: 행사 이벤트 이름을 변경할 때 트래킹 코드 삽입
jinhokim98 Jan 27, 2025
de2d296
feat: 이미지 추가할 때 이미지 추가횟수 이벤트 발생
jinhokim98 Jan 27, 2025
09ad562
feat: 유저 이름 변경 시 트래킹 코드 이벤트 발생
jinhokim98 Jan 27, 2025
37c2e28
feat: 은행 이름을 트래킹 하는 코드 추가
jinhokim98 Jan 27, 2025
e6629ad
feat: 회원 탈퇴를 트래킹하는 코드 추가
jinhokim98 Jan 27, 2025
50b7cdc
feat: 행사 삭제 관련 트래킹 코드 추가
jinhokim98 Jan 27, 2025
a05a2b6
feat: qr code 공유 방식 트래킹 코드 추가
jinhokim98 Jan 27, 2025
d8a0725
refactor: track + 동사 + 목적어 형태로 메서드 명 수정
jinhokim98 Jan 30, 2025
1d216f1
refactor: 범용적으로 사용할 수 있도록 컴포넌트 이름 변경
jinhokim98 Jan 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import {useEffect} from 'react';

import {useAmplitudeStore} from '@store/amplitudeStore';
import {init} from '@amplitude/analytics-browser';

const AmplitudeInitializer = ({children}: React.PropsWithChildren) => {
const {amplitude} = useAmplitudeStore();

useEffect(() => {
amplitude.init(process.env.AMPLITUDE_KEY, undefined, {
init(process.env.AMPLITUDE_KEY, undefined, {
defaultTracking: true,
});
}, []);
Expand Down
5 changes: 5 additions & 0 deletions client/src/components/CreatedEventList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {useCreatedEventsPageContext} from '@pages/main/events/CreatedEvent.conte
import {CreatedEvent} from 'types/serviceType';
import {CreatedEventItem} from '@components/Design/components/CreatedEventItem/CreatedEventItem';

import useAmplitude from '@hooks/useAmplitude';

import {FixedButton, Flex, Input} from '@components/Design';

type CreatedEventListProps = {
Expand All @@ -17,8 +19,11 @@ export const CreatedEventList = ({createdEvents, eventName, onSearch, placeholde
const setViewMode = () => handleMode('view');

const {deleteEvents} = useRequestDeleteEvents();
const {trackEventDelete} = useAmplitude();

const onDeleteClick = async () => {
trackEventDelete('multi');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deleteEvent가 성공하고 나서야 tracking 되어야 하지 않나 싶어요!!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 맞네요! 수정했습니다


const selectedEventsId = selectedEvents.map(event => event.eventId);
await deleteEvents({eventIds: selectedEventsId});
handleMode('view');
Expand Down
1 change: 1 addition & 0 deletions client/src/components/Design/components/Tabs/Tab.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {FlexProps} from '../Flex/Flex.type';
export interface TabProps {
label: string;
content: React.ReactNode;
onClick?: () => void;
}

export interface TabsCustomProps {
Expand Down
7 changes: 6 additions & 1 deletion client/src/components/Design/components/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,12 @@ const Tabs: React.FC<TabsProps> = ({children, tabsContainerStyle}) => {
id={`tab-${tabItem.props.label}`}
css={tabItemStyle}
aria-selected={isActive(index)}
onClick={() => setActiveTabIndex(index)}
onClick={() => {
if (tabItem.props.onClick) {
tabItem.props.onClick();
}
setActiveTabIndex(index);
}}
aria-controls={`tabpanel-${tabItem.props.label}`}
>
<Text css={tabTextStyle({theme, selected: isActive(index)})} size={isActive(index) ? 'bodyBold' : 'body'}>
Expand Down
3 changes: 3 additions & 0 deletions client/src/components/EditAccountPageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import BankSelectModal from '@components/Modal/BankSelectModal/BankSelectModal';
import {BankAccount, BankName} from 'types/serviceType';

import useAccount from '@hooks/useAccount';
import useAmplitude from '@hooks/useAmplitude';

import {FixedButton, Flex, FunnelLayout, Input, MainLayout, Top, TopNav} from '@components/Design';

Expand All @@ -22,6 +23,7 @@ const EditAccountPageView = ({
redirectUrlOnSubmit,
}: EditAccountPageProps) => {
const navigate = useNavigate();
const {trackBankName} = useAmplitude();

const [isBottomSheetOpen, setIsBottomSheetOpen] = useState(false);

Expand All @@ -42,6 +44,7 @@ const EditAccountPageView = ({

const enrollAccountAndRedirectTo = async () => {
await enrollAccount();
trackBankName(bankName);

navigate(redirectUrlOnSubmit);
};
Expand Down
20 changes: 5 additions & 15 deletions client/src/components/ShareEventButton/DesktopShareEventButton.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,25 @@
import {useNavigate} from 'react-router-dom';

import toast from '@hooks/useToast/toast';

import {Dropdown, DropdownButton} from '@components/Design';

import getEventIdByUrl from '@utils/getEventIdByUrl';

type DesktopShareEventButtonProps = React.PropsWithChildren<React.HTMLAttributes<HTMLButtonElement>> & {
onCopy: () => Promise<void>;
copyShare: () => Promise<void>;
qrShare: () => void;
};

const DesktopShareEventButton = ({onCopy}: DesktopShareEventButtonProps) => {
const DesktopShareEventButton = ({copyShare, qrShare}: DesktopShareEventButtonProps) => {
const copyAndToast = async () => {
await onCopy();
await copyShare();
toast.confirm('링크가 복사되었어요 :) \n참여자들에게 링크를 공유해 주세요!', {
showingTime: 3000,
position: 'bottom',
});
};

const navigate = useNavigate();
const eventId = getEventIdByUrl();

const navigateQRPage = () => {
navigate(`/event/${eventId}/qrcode`);
};

return (
<Dropdown base="button" baseButtonText="정산 초대하기">
<DropdownButton text="링크 복사하기" onClick={copyAndToast} />
<DropdownButton text="QR코드로 초대하기" onClick={navigateQRPage} />
<DropdownButton text="QR코드로 초대하기" onClick={qrShare} />
</Dropdown>
);
};
Expand Down
15 changes: 3 additions & 12 deletions client/src/components/ShareEventButton/MobileShareEventButton.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import {useNavigate} from 'react-router-dom';

import toast from '@hooks/useToast/toast';

import {Dropdown, DropdownButton} from '@components/Design';

import getEventIdByUrl from '@utils/getEventIdByUrl';
import initKakao from '@utils/initKakao';

type MobileShareEventButtonProps = {
copyShare: () => Promise<void>;
kakaoShare: () => void;
qrShare: () => void;
};

const MobileShareEventButton = ({copyShare, kakaoShare}: MobileShareEventButtonProps) => {
const MobileShareEventButton = ({copyShare, kakaoShare, qrShare}: MobileShareEventButtonProps) => {
const copyAndToast = async () => {
await copyShare();
toast.confirm('링크가 복사되었어요 :) \n참여자들에게 링크를 공유해 주세요!', {
Expand All @@ -21,17 +19,10 @@ const MobileShareEventButton = ({copyShare, kakaoShare}: MobileShareEventButtonP
});
};

const navigate = useNavigate();
const eventId = getEventIdByUrl();

const navigateQRPage = () => {
navigate(`/event/${eventId}/qrcode`);
};

return (
<Dropdown base="button" baseButtonText="정산 초대하기" onBaseButtonClick={initKakao}>
<DropdownButton text="링크 복사하기" onClick={copyAndToast} />
<DropdownButton text="QR코드로 초대하기" onClick={navigateQRPage} />
<DropdownButton text="QR코드로 초대하기" onClick={qrShare} />
<DropdownButton text="카카오톡으로 초대하기" onClick={kakaoShare} />
</Dropdown>
);
Expand Down
16 changes: 15 additions & 1 deletion client/src/hooks/queries/user/useRequestGetUserInfo.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import {useSuspenseQuery} from '@tanstack/react-query';
import {useEffect} from 'react';

import {requestGetUserInfo} from '@apis/request/user';
import {UserInfo} from 'types/serviceType';

import {useAuthStore} from '@store/authStore';

import QUERY_KEYS from '@constants/queryKeys';

export type UseRequestGetUserInfo = ReturnType<typeof useRequestGetUserInfo>;
Expand All @@ -20,16 +23,27 @@ const useRequestGetUserInfo = ({enableInitialData = true}: UseRequestGetUserInfo
bankName: '',
};

const {data, ...rest} = useSuspenseQuery({
const {data, isSuccess, isError, ...rest} = useSuspenseQuery({
queryKey: [QUERY_KEYS.userInfo],
queryFn: () => requestGetUserInfo(),
// quernFn은 ErrorCatcher 구독을 하지 않으며 오류가 났을 경우 로그인 화면을 띄워야하므로 initialData를 설정했습니다.
initialData: enableInitialData ? initialData : undefined,
initialDataUpdatedAt: enableInitialData ? 0 : undefined,
});

const {updateKakaoAuth} = useAuthStore();

useEffect(() => {
if (isSuccess) {
updateKakaoAuth(!data.isGuest);
} else if (isError) {
updateKakaoAuth(false);
}
}, [isSuccess, isError]);

return {
userInfo: {...data},
isSuccess,
...rest,
};
};
Expand Down
4 changes: 3 additions & 1 deletion client/src/hooks/useAddImagesPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import getEventIdByUrl from '@utils/getEventIdByUrl';
import useRequestGetImages from './queries/images/useRequestGetImages';
import useRequestPostImages from './queries/images/useRequestPostImages';
import useRequestDeleteImage from './queries/images/useRequestDeleteImages';
import useAmplitude from './useAmplitude';

type LoadedImage = ImageFile;
type AddedImage = File;
Expand All @@ -31,6 +32,7 @@ const useAddImagesPage = () => {

const {postImages, isPending} = useRequestPostImages();
const {deleteImage} = useRequestDeleteImage();
const {trackUploadImageCount} = useAmplitude();

useEffect(() => {
if (!isSuccess) return;
Expand Down Expand Up @@ -65,7 +67,7 @@ const useAddImagesPage = () => {
formData.append('images', addedImages[i], addedImages[i].name);
}

await postImages({formData});
await postImages({formData}, {onSuccess: () => trackUploadImageCount(addedImages.length)});
}

navigate(`/event/${eventId}/admin`);
Expand Down
Loading
Loading