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

[Fix]: qa 반영 #96

Merged
merged 10 commits into from
Aug 11, 2024
2 changes: 1 addition & 1 deletion src/apis/discord/discordApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const discordApi = {
});
return response.data;
},
GET_DISCORD_JOIN: async (name: string) => {
GET_DISCORD_JOIN: async (name: string): Promise<{ isJoined: boolean }> => {
const response = await apiClient.get('/onboarding/check-discord-join', {
params: {
username: name
Expand Down
63 changes: 63 additions & 0 deletions src/components/auth/guard/VerificationGuard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import RoutePath from '@/routes/routePath';
import { toast } from 'react-toastify';
import { useNavigate } from 'react-router-dom';
import { PropsWithChildren, useEffect } from 'react';
import memberApi from '@/apis/member/memberApi';
import { useQuery } from '@tanstack/react-query';

type GuardType = 'StudentVerification' | 'Discord' | 'SignUp' | 'Bevy';

interface VerificationGuardProps extends PropsWithChildren {
guardType: GuardType;
}
/** 기본 정보, 디스코드 정보, 이메일 정보가 인증되어 있는지에 대한 가드 */

export default function VerificationGuard({
guardType,
children
}: VerificationGuardProps) {
const navigate = useNavigate();
const { data } = useQuery({
queryKey: ['member'],
queryFn: memberApi.GET_DASHBOARD
});

useEffect(() => {
if (!data) return;

if (
guardType === 'SignUp' &&
data.member.associateRequirement.infoStatus === 'SATISFIED'
) {
toast.error('기본 정보를 이미 입력했습니다.');
navigate(RoutePath.Dashboard);
return;
}
if (
guardType === 'Discord' &&
data.member.associateRequirement.discordStatus === 'SATISFIED'
) {
toast.error('디스코드 연동을 이미 완료했습니다.');
navigate(RoutePath.Dashboard);
return;
}
if (
guardType === 'StudentVerification' &&
data.member.associateRequirement.univStatus === 'SATISFIED'
) {
toast.error('재학생 인증을 이미 완료했습니다.');
navigate(RoutePath.Dashboard);
return;
}
if (
guardType === 'Bevy' &&
data.member.associateRequirement.bevyStatus === 'SATISFIED'
) {
toast.error('bevy 가입을 이미 완료했습니다.');
navigate(RoutePath.Dashboard);
return;
}
}, [data, guardType, navigate]);

return children;
}
8 changes: 3 additions & 5 deletions src/components/discordConnect/DiscordName.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ export const DiscordName = ({ onNext }: { onNext: () => void }) => {
const { getValues, control, trigger, setError } =
useFormContext<DiscordFormValues>();

const { checkDuplicate, data, isSuccess } = usePostDiscordName(
getValues('discordUsername')
);
const { checkDuplicate, data, isSuccess } = usePostDiscordName();

useEffect(() => {
if (isSuccess) {
Expand All @@ -36,14 +34,14 @@ export const DiscordName = ({ onNext }: { onNext: () => void }) => {
const handleNextClick = useCallback(async () => {
const isValid = await trigger('discordUsername');
if (isValid) {
checkDuplicate();
checkDuplicate(getValues('discordUsername'));
} else {
setError('discordUsername', {
type: 'manual',
message: '하단 규정에 맞춰 작성해주세요.'
});
}
}, [checkDuplicate, setError, trigger]);
}, [checkDuplicate, getValues, setError, trigger]);

return (
<>
Expand Down
8 changes: 3 additions & 5 deletions src/components/discordConnect/DiscordNickName.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ import Divider from 'wowds-ui/Divider';
export const DiscordNickName = ({ onNext }: { onNext: () => void }) => {
const { getValues, control, setError, clearErrors, trigger } =
useFormContext<DiscordFormValues>();
const { checkDuplicate, data, isSuccess } = usePostDiscordNickname(
getValues('discordNickname')
);
const { checkDuplicate, data, isSuccess } = usePostDiscordNickname();

useEffect(() => {
if (isSuccess) {
Expand All @@ -33,14 +31,14 @@ export const DiscordNickName = ({ onNext }: { onNext: () => void }) => {
const handleNextClick = useCallback(async () => {
const isValid = await trigger('discordNickname');
if (isValid) {
checkDuplicate();
checkDuplicate(getValues('discordNickname'));
} else {
setError('discordNickname', {
type: 'manual',
message: '하단 규정에 맞춰 작성해주세요.'
});
}
}, [checkDuplicate, setError, trigger]);
}, [checkDuplicate, getValues, setError, trigger]);

return (
<>
Expand Down
44 changes: 41 additions & 3 deletions src/components/discordConnect/JoinServer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,44 @@ import { useFormContext } from 'react-hook-form';
import useGetDiscordJoined from '@/hooks/query/useGetDiscordJoined';
import { DiscordFormValues } from '@/types/discord';
import RoutePath from '@/routes/routePath';
import { useState, useEffect } from 'react';

const FETCH_INTERVAL = 5000;

export const JoinServer = ({ onNext }: { onNext: () => void }) => {
const { getValues } = useFormContext<DiscordFormValues>();
const { data } = useGetDiscordJoined(getValues('discordUsername'));
const [callQuery, setCallQuery] = useState(false);

// 초기에 5초 후에 isEnabled를 true로 설정
useEffect(() => {
const timer = setTimeout(() => {
setCallQuery(true);
}, FETCH_INTERVAL);

return () => clearTimeout(timer);
}, []);

const { data, refetch } = useGetDiscordJoined(
getValues('discordUsername'),
callQuery
);

// data가 변경될 때마다 refetch를 호출하여 최신 상태를 가져옴
useEffect(() => {
if (callQuery) {
refetch();
}
}, [callQuery, refetch]);

// data가 변경될 때마다 버튼 상태를 업데이트
useEffect(() => {
if (data) {
if (data.isJoined) setCallQuery(false); // 합류가 확인되면 더 이상 fetch하지 않음
}
}, [data]);
Copy link
Member

Choose a reason for hiding this comment

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

image

p4;
useQuery쪽에서 설정하신 refetchInterval 옵션만으로 5초마다 폴링을 해볼 수 있을 것 같아요. 해당 로직이 꼭 필요한 이유가 있을까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

// data가 변경될 때마다 refetch를 호출하여 최신 상태를 가져옴
  useEffect(() => {
    if (callQuery) {
      refetch();
    }
  }, [callQuery, refetch]);

저도 이 부분은 refetchInterval 을 통해서 5초마다 refetch 될 거라고 생각했는데 확인하셨을 때 잘 동작하지 않았던 걸까용?! @eugene028

Copy link
Contributor

Choose a reason for hiding this comment

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

앗 제가 이거저거 테스트해보면서 별다른 고려없이 refetch 넣었던 것 같아요~ 요거 수정해두겠습니다


console.log(callQuery);
SeieunYoo marked this conversation as resolved.
Show resolved Hide resolved

return (
<>
<Flex direction="column" align="flex-start">
Expand All @@ -27,7 +61,7 @@ export const JoinServer = ({ onNext }: { onNext: () => void }) => {
</Flex>
<Flex direction="column" gap="xs">
<TextButton
text=" GDSC Hongik 공식 디스코드 서버↗︎"
text="GDSC Hongik 공식 디스코드 서버↗︎"
style={{ color: color.discord }}
onClick={() => window.open(RoutePath.GDSCHongikDiscord, '_blank')}
/>
Expand All @@ -38,7 +72,11 @@ export const JoinServer = ({ onNext }: { onNext: () => void }) => {
}}
disabled={!data?.isJoined}
style={{ maxWidth: '100%' }}>
합류가 확인되면 넘어갈 수 있어요.
{callQuery
? '합류 여부를 확인 중이에요.'
: data?.isJoined
? '합류가 확인되었어요.'
: '합류가 확인되지 않았어요.'}
</Button>

<Text
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/mutation/usePostDiscordName.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import discordApi from '@/apis/discord/discordApi';
import { useMutation } from '@tanstack/react-query';

export function usePostDiscordName(userName: string) {
export function usePostDiscordName() {
const { mutate: checkDuplicate, ...rest } = useMutation({
mutationFn: () => discordApi.GET_DISCORD_NAME(userName)
mutationFn: (userName: string) => discordApi.GET_DISCORD_NAME(userName)
});
return { checkDuplicate, ...rest };
}
4 changes: 2 additions & 2 deletions src/hooks/mutation/usePostDiscordNickname.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import discordApi from '@/apis/discord/discordApi';
import { useMutation } from '@tanstack/react-query';

export function usePostDiscordNickname(nickname: string) {
export function usePostDiscordNickname() {
const { mutate: checkDuplicate, ...rest } = useMutation({
mutationFn: () => discordApi.GET_DISCORD_NICKNAME(nickname)
mutationFn: (nickname: string) => discordApi.GET_DISCORD_NICKNAME(nickname)
});
return { checkDuplicate, ...rest };
}
10 changes: 8 additions & 2 deletions src/hooks/query/useGetDiscordJoined.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ import discordApi from '@/apis/discord/discordApi';
import QueryKeys from '@/constants/queryKey';
import { useQuery } from '@tanstack/react-query';

export default function useGetDiscordJoined(username: string) {
const FETCH_INTERVAL = 5000;
export default function useGetDiscordJoined(
username: string,
isEnabled: boolean
) {
const query = useQuery({
queryKey: [QueryKeys.DiscordJoined],
queryFn: () => discordApi.GET_DISCORD_JOIN(username),
refetchOnWindowFocus: true
refetchOnWindowFocus: true,
refetchInterval: FETCH_INTERVAL,
enabled: isEnabled
});

return query;
Expand Down
2 changes: 1 addition & 1 deletion src/pages/DiscordConnect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import useCustomBack from '@/hooks/common/useCutomBack';

const steps = ['이름 설정', '별명 설정', '서버 합류', '서버 연동', '연동 완료'];

export const DicordConnect = () => {
export const DiscordConnect = () => {
const { Funnel, Step, setStep, currentStep } = useFunnel(steps[0]);

const methods = useForm<DiscordFormValues>({
Expand Down
55 changes: 47 additions & 8 deletions src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ import {
PaymentsFail,
PaymentsCheckout
} from '@/pages';
import { DicordConnect } from '@/pages/DiscordConnect';
import { DiscordConnect } from '@/pages/DiscordConnect';
import { DiscordGuide } from '@/pages/DiscordGuide';
import { Suspense } from 'react';
import PaymentAccessGuard from '@/components/auth/guard/PaymentAccessGuard';
import VerificationGuard from '@/components/auth/guard/VerificationGuard';

const sentryCreateBrowserRouter =
Sentry.wrapCreateBrowserRouter(createBrowserRouter);
Expand Down Expand Up @@ -57,17 +58,28 @@ const router = sentryCreateBrowserRouter([
{
index: true,
element: (
<Suspense fallback="..loading">
<StudentVerification />
</Suspense>
<VerificationGuard guardType="StudentVerification">
<Suspense fallback="..loading">
<StudentVerification />
</Suspense>
</VerificationGuard>
)
}
]
},
{
path: RoutePath.Signup,
element: <AuthAccessGuard />,
children: [{ index: true, element: <SignUp /> }]
children: [
{
index: true,
element: (
<VerificationGuard guardType="SignUp">
<SignUp />
</VerificationGuard>
)
}
]
},
{
path: RoutePath.Home,
Expand All @@ -79,19 +91,46 @@ const router = sentryCreateBrowserRouter([
},
{
path: RoutePath.Discord,
element: <JoinDiscord />
children: [
{
index: true,
element: (
<VerificationGuard guardType="Discord">
<JoinDiscord />
</VerificationGuard>
)
}
]
},
{
path: RoutePath.DiscordConnect,
element: <DicordConnect />
children: [
{
index: true,
element: (
<VerificationGuard guardType="Discord">
<DiscordConnect />
</VerificationGuard>
)
}
]
},
{
path: RoutePath.DiscordGuide,
element: <DiscordGuide />
},
{
path: RoutePath.Bevy,
element: <Bevy />
children: [
{
index: true,
element: (
<VerificationGuard guardType="Bevy">
<Bevy />
</VerificationGuard>
)
}
]
}
]
},
Expand Down
Loading