Skip to content

Commit cb808fa

Browse files
refactor: mainCard(온보딩) 도메인 종속되는 funnel 구조 useOnboardingFunnel으로 2차 추상화
1 parent d22d6b5 commit cb808fa

File tree

2 files changed

+170
-131
lines changed

2 files changed

+170
-131
lines changed

apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx

Lines changed: 13 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Progress, Button, sendGAEvent } from '@pinback/design-system/ui';
2-
import { useState, useEffect, lazy, Suspense } from 'react';
1+
import { Progress, Button } from '@pinback/design-system/ui';
2+
import { lazy, Suspense } from 'react';
33
import { motion, AnimatePresence } from 'framer-motion';
44
import SocialLoginStep from './step/SocialLoginStep';
55
const StoryStep = lazy(() => import('./step/StoryStep'));
@@ -8,21 +8,13 @@ const AlarmStep = lazy(() => import('./step/AlarmStep'));
88
const MacStep = lazy(() => import('./step/MacStep'));
99
const FinalStep = lazy(() => import('./step/FinalStep'));
1010
import { cva } from 'class-variance-authority';
11-
import { usePostSignUp } from '@shared/apis/queries';
12-
import { firebaseConfig } from '../../../../firebase-config';
13-
import { initializeApp } from 'firebase/app';
14-
import { getMessaging, getToken } from 'firebase/messaging';
15-
import { registerServiceWorker } from '@pages/onBoarding/utils/registerServiceWorker';
16-
import { AlarmsType } from '@constants/alarms';
17-
import { normalizeTime } from '@pages/onBoarding/utils/formatRemindTime';
18-
import { useFunnel } from '@shared/hooks/useFunnel';
1911
const stepProgress = [{ progress: 33 }, { progress: 66 }, { progress: 100 }];
2012
import {
2113
Step,
22-
stepOrder,
2314
StepType,
2415
storySteps,
2516
} from '@pages/onBoarding/constants/onboardingSteps';
17+
import { useOnboardingFunnel } from '@pages/onBoarding/hooks/useOnboardingFunnel';
2618

2719
const variants = {
2820
slideIn: (direction: number) => ({
@@ -50,74 +42,16 @@ const CardStyle = cva(
5042
);
5143

5244
const MainCard = () => {
53-
const { mutate: postSignData } = usePostSignUp();
54-
55-
const { currentStep: step, currentIndex, setStep, goNext, goPrev } =
56-
useFunnel<StepType>({
57-
steps: stepOrder,
58-
initialStep: Step.STORY_0,
59-
});
60-
const [direction, setDirection] = useState(0);
61-
const [alarmSelected, setAlarmSelected] = useState<1 | 2 | 3>(1);
62-
const [isMac, setIsMac] = useState(false);
63-
const [userEmail, setUserEmail] = useState('');
64-
const [remindTime, setRemindTime] = useState('09:00');
65-
const [fcmToken, setFcmToken] = useState<string | null>(null);
66-
const [jobShareAgree, setJobShareAgree] = useState(true);
67-
68-
useEffect(() => {
69-
const storedEmail = localStorage.getItem('email');
70-
if (storedEmail) {
71-
setUserEmail(storedEmail);
72-
}
73-
}, []);
74-
75-
const app = initializeApp(firebaseConfig);
76-
const messaging = getMessaging(app);
77-
78-
const requestFCMToken = async (): Promise<string | null> => {
79-
try {
80-
const permission = await Notification.requestPermission();
81-
registerServiceWorker();
82-
83-
if (permission !== 'granted') {
84-
alert('알림 권한 허용이 필요합니다!');
85-
return null;
86-
}
87-
88-
const forFcmtoken = await getToken(messaging, {
89-
vapidKey: import.meta.env.VITE_FIREBASE_VAPID_KEY,
90-
});
91-
92-
if (forFcmtoken) {
93-
return forFcmtoken;
94-
} else {
95-
alert('토큰 생성 실패. 다시 시도해주세요.');
96-
return null;
97-
}
98-
} catch (error) {
99-
console.error('FCM 토큰 받는 도중 오류:', error);
100-
alert('알림 설정 중 오류가 발생했습니다. 다시 시도해주세요.');
101-
return null;
102-
}
103-
};
104-
105-
useEffect(() => {
106-
const ua = navigator.userAgent.toLowerCase();
107-
if (ua.includes('mac os') || ua.includes('iphone') || ua.includes('ipad')) {
108-
setIsMac(true);
109-
}
110-
111-
(async () => {
112-
const token = await requestFCMToken();
113-
if (token) {
114-
setFcmToken(token);
115-
localStorage.setItem('FcmToken', token);
116-
} else {
117-
alert('푸시 알람 설정 에러');
118-
}
119-
})();
120-
}, []);
45+
const {
46+
step,
47+
direction,
48+
alarmSelected,
49+
jobShareAgree,
50+
setAlarmSelected,
51+
setJobShareAgree,
52+
nextStep,
53+
prevStep,
54+
} = useOnboardingFunnel();
12155

12256
const renderStep = () => {
12357
switch (step) {
@@ -149,58 +83,6 @@ const MainCard = () => {
14983
}
15084
};
15185

152-
const nextStep = async () => {
153-
const next = stepOrder[currentIndex + 1];
154-
const isAlarmStep = step === Step.ALARM;
155-
const isFinalStep = step === Step.FINAL;
156-
const isMacStep = next === Step.MAC;
157-
const shouldSkipMacStep = isMacStep && !isMac;
158-
159-
if (isAlarmStep) {
160-
if (alarmSelected === 1) setRemindTime('09:00');
161-
else if (alarmSelected === 2) setRemindTime('20:00');
162-
else {
163-
const raw = AlarmsType[alarmSelected - 1].time;
164-
setRemindTime(normalizeTime(raw));
165-
}
166-
}
167-
168-
if (shouldSkipMacStep) {
169-
setDirection(1);
170-
setStep(Step.FINAL);
171-
return;
172-
}
173-
174-
if (isFinalStep) {
175-
postSignData(
176-
{ email: userEmail, remindDefault: remindTime, fcmToken },
177-
{
178-
onSuccess: () => (window.location.href = '/'),
179-
onError: () => {
180-
const savedEmail = localStorage.getItem('email');
181-
if (savedEmail) window.location.href = '/';
182-
},
183-
}
184-
);
185-
return;
186-
}
187-
188-
setDirection(1);
189-
goNext();
190-
sendGAEvent(
191-
`onboard-step-${currentIndex + 1}`,
192-
`onboard-step-${currentIndex + 1}`,
193-
`onboard-step-${currentIndex + 1}`
194-
);
195-
};
196-
197-
const prevStep = () => {
198-
if (currentIndex > 0) {
199-
setDirection(-1);
200-
goPrev();
201-
}
202-
};
203-
20486
return (
20587
<div
20688
className={CardStyle({
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import { sendGAEvent } from '@pinback/design-system/ui';
2+
import { usePostSignUp } from '@shared/apis/queries';
3+
import { useFunnel } from '@shared/hooks/useFunnel';
4+
import { useCallback, useEffect, useState } from 'react';
5+
import { AlarmsType } from '@constants/alarms';
6+
import { normalizeTime } from '@pages/onBoarding/utils/formatRemindTime';
7+
import { registerServiceWorker } from '@pages/onBoarding/utils/registerServiceWorker';
8+
import { Step, stepOrder, StepType } from '@pages/onBoarding/constants/onboardingSteps';
9+
import { firebaseConfig } from '../../../firebase-config';
10+
import { getApp, getApps, initializeApp } from 'firebase/app';
11+
import { getMessaging, getToken } from 'firebase/messaging';
12+
13+
type AlarmSelection = 1 | 2 | 3;
14+
15+
export function useOnboardingFunnel() {
16+
const { mutate: postSignData } = usePostSignUp();
17+
const { currentStep: step, currentIndex, setStep, goNext, goPrev } =
18+
useFunnel<StepType>({
19+
steps: stepOrder,
20+
initialStep: Step.STORY_0,
21+
});
22+
23+
const [direction, setDirection] = useState(0);
24+
const [alarmSelected, setAlarmSelected] = useState<AlarmSelection>(1);
25+
const [isMac, setIsMac] = useState(false);
26+
const [userEmail, setUserEmail] = useState('');
27+
const [remindTime, setRemindTime] = useState('09:00');
28+
const [fcmToken, setFcmToken] = useState<string | null>(null);
29+
const [jobShareAgree, setJobShareAgree] = useState(true);
30+
31+
useEffect(() => {
32+
const storedEmail = localStorage.getItem('email');
33+
if (storedEmail) {
34+
setUserEmail(storedEmail);
35+
}
36+
}, []);
37+
38+
const requestFCMToken = useCallback(async (): Promise<string | null> => {
39+
try {
40+
const app = getApps().length > 0 ? getApp() : initializeApp(firebaseConfig);
41+
const messaging = getMessaging(app);
42+
const permission = await Notification.requestPermission();
43+
registerServiceWorker();
44+
45+
if (permission !== 'granted') {
46+
alert('알림 권한 허용이 필요합니다!');
47+
return null;
48+
}
49+
50+
const forFcmtoken = await getToken(messaging, {
51+
vapidKey: import.meta.env.VITE_FIREBASE_VAPID_KEY,
52+
});
53+
54+
if (forFcmtoken) {
55+
return forFcmtoken;
56+
}
57+
58+
alert('토큰 생성 실패. 다시 시도해주세요.');
59+
return null;
60+
} catch {
61+
alert('알림 설정 중 오류가 발생했습니다. 다시 시도해주세요.');
62+
return null;
63+
}
64+
}, []);
65+
66+
useEffect(() => {
67+
const ua = navigator.userAgent.toLowerCase();
68+
if (ua.includes('mac os') || ua.includes('iphone') || ua.includes('ipad')) {
69+
setIsMac(true);
70+
}
71+
72+
(async () => {
73+
const token = await requestFCMToken();
74+
if (token) {
75+
setFcmToken(token);
76+
localStorage.setItem('FcmToken', token);
77+
} else {
78+
alert('푸시 알람 설정 에러');
79+
}
80+
})();
81+
}, [requestFCMToken]);
82+
83+
const nextStep = useCallback(async () => {
84+
const next = stepOrder[currentIndex + 1];
85+
const isAlarmStep = step === Step.ALARM;
86+
const isFinalStep = step === Step.FINAL;
87+
const isMacStep = next === Step.MAC;
88+
const shouldSkipMacStep = isMacStep && !isMac;
89+
90+
if (isAlarmStep) {
91+
if (alarmSelected === 1) setRemindTime('09:00');
92+
else if (alarmSelected === 2) setRemindTime('20:00');
93+
else {
94+
const raw = AlarmsType[alarmSelected - 1].time;
95+
setRemindTime(normalizeTime(raw));
96+
}
97+
}
98+
99+
if (shouldSkipMacStep) {
100+
setDirection(1);
101+
setStep(Step.FINAL);
102+
return;
103+
}
104+
105+
if (isFinalStep) {
106+
postSignData(
107+
{ email: userEmail, remindDefault: remindTime, fcmToken },
108+
{
109+
onSuccess: () => (window.location.href = '/'),
110+
onError: () => {
111+
const savedEmail = localStorage.getItem('email');
112+
if (savedEmail) window.location.href = '/';
113+
},
114+
}
115+
);
116+
return;
117+
}
118+
119+
setDirection(1);
120+
goNext();
121+
sendGAEvent(
122+
`onboard-step-${currentIndex + 1}`,
123+
`onboard-step-${currentIndex + 1}`,
124+
`onboard-step-${currentIndex + 1}`
125+
);
126+
}, [
127+
alarmSelected,
128+
currentIndex,
129+
fcmToken,
130+
goNext,
131+
isMac,
132+
postSignData,
133+
remindTime,
134+
setStep,
135+
step,
136+
userEmail,
137+
]);
138+
139+
const prevStep = useCallback(() => {
140+
if (currentIndex > 0) {
141+
setDirection(-1);
142+
goPrev();
143+
}
144+
}, [currentIndex, goPrev]);
145+
146+
return {
147+
step,
148+
currentIndex,
149+
direction,
150+
alarmSelected,
151+
jobShareAgree,
152+
setAlarmSelected,
153+
setJobShareAgree,
154+
nextStep,
155+
prevStep,
156+
};
157+
}

0 commit comments

Comments
 (0)