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
29 changes: 26 additions & 3 deletions src/components/discordConnect/JoinServer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,29 @@ 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 } = useGetDiscordJoined(getValues('discordUsername'), callQuery);

useEffect(() => {
if (data?.isJoined) setCallQuery(false);
}, [data]);

return (
<>
<Flex direction="column" align="flex-start">
Expand All @@ -27,7 +46,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 +57,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
3 changes: 1 addition & 2 deletions src/utils/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export const isAuthenticated = () => {
const isLogin = sessionStorage.getItem('isLogin');

if (isLogin === 'true') return true;
else return false;
return isLogin === 'true';
};
Loading