diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..0506d83
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,2 @@
+vite.config.ts
+jest.config.ts
\ No newline at end of file
diff --git a/.eslintrc.json b/.eslintrc.json
index ff33cbd..41f68a8 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -33,6 +33,9 @@
"typescript": {
"alwaysTryTypes": true
}
+ },
+ "react": {
+ "version": "detect"
}
},
"rules": {
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 390dc1c..30222da 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -19,7 +19,7 @@ jobs:
uses: actions/checkout@master
- name: Cache node modules
- uses: actions/cache@v1
+ uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.OS }}-build-${{ hashFiles('**/package-lock.json') }}
@@ -41,11 +41,14 @@ jobs:
- name: Install Dependencies
run: pnpm install --no-frozen-lockfile --force
+ - name: Lint Code
+ run: pnpm lint
+
- name: Build
run: CI='' pnpm run build
- name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@v1
+ uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
diff --git a/index.html b/index.html
index bc79258..f74e58e 100644
--- a/index.html
+++ b/index.html
@@ -5,36 +5,6 @@
-
GDSC_KNU_OFFICIAL
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/public/ApplyInquiry.png b/public/ApplyInquiry.png
new file mode 100644
index 0000000..3d62dab
Binary files /dev/null and b/public/ApplyInquiry.png differ
diff --git a/public/CommingSoon.png b/public/CommingSoon.png
new file mode 100644
index 0000000..6828854
Binary files /dev/null and b/public/CommingSoon.png differ
diff --git a/src/apis/hooks/apply/ApplyInquiryAPI.ts b/src/apis/hooks/apply/ApplyInquiryAPI.ts
index c681e78..44d8e3b 100644
--- a/src/apis/hooks/apply/ApplyInquiryAPI.ts
+++ b/src/apis/hooks/apply/ApplyInquiryAPI.ts
@@ -14,6 +14,12 @@ export const ApplyInquiryAPI = async (name: string, studentNumber: string) => {
if (typedError.code === 409) {
alert('최종지원된 서류는 확인하실 수 없습니다.');
throw new Error('최종지원된 서류는 확인하실 수 없습니다.');
+ } else if (typedError.code === 403) {
+ alert('본인이 아닌 지원자의 서류는 확인하실 수 없습니다.');
+ throw new Error('본인이 아닌 지원자의 서류는 확인하실 수 없습니다.');
+ } else {
+ alert('서버 오류가 발생했습니다. 잠시 후 다시 시도해주세요.');
+ throw new Error('서버 오류가 발생했습니다. 잠시 후 다시 시도해주세요.');
}
}
throw new Error('아직 서류를 제출하지 않으셨습니다.');
diff --git a/src/components/feature/auth/AuthModal.tsx b/src/components/feature/auth/AuthModal.tsx
index 8e4f4b3..37ba981 100644
--- a/src/components/feature/auth/AuthModal.tsx
+++ b/src/components/feature/auth/AuthModal.tsx
@@ -3,7 +3,6 @@ import Text from '@gdsc/components/common/typography/Text';
import { AuthBox } from '@gdsc/styles/AuthModalStyle';
import { displayCenter } from '@gdsc/styles/LayoutStyle';
-// eslint-disable-next-line import/no-unresolved
import logo from '/GDSC.svg';
import styled from '@emotion/styled';
diff --git a/src/hooks/useScrollTracker.ts b/src/hooks/useScrollTracker.ts
new file mode 100644
index 0000000..144fd0c
--- /dev/null
+++ b/src/hooks/useScrollTracker.ts
@@ -0,0 +1,27 @@
+import { useEffect } from 'react';
+
+import { handleScroll } from '@gdsc/utils/anlytics';
+
+// 유틸리티 함수 경로
+
+const useScrollTracker = () => {
+ useEffect(() => {
+ const onScroll = () => {
+ const scrollPosition = window.scrollY;
+ const scrollHeight =
+ document.documentElement.scrollHeight - window.innerHeight;
+ const scrolledPercentage = (scrollPosition / scrollHeight) * 100;
+
+ if (scrolledPercentage >= 50) {
+ handleScroll();
+ }
+ };
+
+ window.addEventListener('scroll', onScroll);
+ return () => {
+ window.removeEventListener('scroll', onScroll);
+ };
+ }, []);
+};
+
+export default useScrollTracker;
diff --git a/src/pages/CommingSoonPage.tsx b/src/pages/CommingSoonPage.tsx
index 6bffaa5..03692e2 100644
--- a/src/pages/CommingSoonPage.tsx
+++ b/src/pages/CommingSoonPage.tsx
@@ -33,42 +33,44 @@ const CommingSoonPage = () => {
const isMobile = useMediaQuery({ query: '(max-width: 500px)' });
return (
-
-
-
- Comming Soon
-
-
- 죄송합니다.
-
현재 개발 중인 페이지입니다.
-
-
-
- 빠른 시일내에
- 사용자 분들께 더 좋은 서비스를 제공할 수 있도록 노력하겠습니다.
-
- 감사합니다.
+ <>
+
+
+
+ Comming Soon
-
- {isMobile && (
-
-
- 홈으로
-
-
- )}
-
+
+ 죄송합니다.
+
현재 개발 중인 페이지입니다.
+
+
+
+ 빠른 시일내에
+ 사용자 분들께 더 좋은 서비스를 제공할 수 있도록 노력하겠습니다.
+
+ 감사합니다.
+
+
+ {isMobile && (
+
+
+ 홈으로
+
+
+ )}
+
+ >
);
};
diff --git a/src/pages/apply/ApplyExPage.tsx b/src/pages/apply/ApplyExPage.tsx
index 087dd8e..d1c3e7d 100644
--- a/src/pages/apply/ApplyExPage.tsx
+++ b/src/pages/apply/ApplyExPage.tsx
@@ -1,13 +1,10 @@
-import { useParams } from 'react-router-dom';
-
import ApplyEx from '@gdsc/pages/apply/components/ApplyEx';
import Star from '@gdsc/pages/main/components/Star';
-import { SEO } from '@gdsc/utils/Seo';
-
import { DisplayLayout } from '@gdsc/styles/LayoutStyle';
import styled from '@emotion/styled';
+import { ApplyExMetaData } from '@gdsc/router/components/MetaData';
const ApplyLayout = styled(DisplayLayout)`
height: 100%;
@@ -18,16 +15,9 @@ const ApplyLayout = styled(DisplayLayout)`
`;
const ApplyExPage = () => {
- const { tech } = useParams();
-
return (
<>
-
+
{[...Array(25)].map((_, index) => (
diff --git a/src/pages/apply/ApplyFormPage.tsx b/src/pages/apply/ApplyFormPage.tsx
index 13c2910..b20a725 100644
--- a/src/pages/apply/ApplyFormPage.tsx
+++ b/src/pages/apply/ApplyFormPage.tsx
@@ -1,23 +1,14 @@
-import { useParams } from 'react-router-dom';
-
import ApplyForm from '@gdsc/pages/apply/components/ApplyForm';
import Star from '@gdsc/pages/main/components/Star';
-import { SEO } from '@gdsc/utils/Seo';
-
import { DisplayLayout } from '@gdsc/styles/LayoutStyle';
-const ApplyFormPage = () => {
- const { tech } = useParams();
+import { ApplyFormMetaData } from '@gdsc/router/components/MetaData';
+const ApplyFormPage = () => {
return (
<>
-
+
{[...Array(25)].map((_, index) => (
diff --git a/src/pages/apply/ApplyPage.tsx b/src/pages/apply/ApplyPage.tsx
index 11ec7c6..fe814df 100644
--- a/src/pages/apply/ApplyPage.tsx
+++ b/src/pages/apply/ApplyPage.tsx
@@ -6,11 +6,10 @@ import ApplyNav from '@gdsc/pages/apply/components/ApplyNav';
import ApplyNavEnd from '@gdsc/pages/apply/components/ApplyNavEnd';
import Star from '@gdsc/pages/main/components/Star';
-import { SEO } from '@gdsc/utils/Seo';
-
import { DisplayLayout } from '@gdsc/styles/LayoutStyle';
import styled from '@emotion/styled';
+import { ApplyMetaData } from '@gdsc/router/components/MetaData';
const ApplyLayout = styled(DisplayLayout)`
height: 100%;
@@ -31,12 +30,7 @@ const ApplyPage = () => {
return (
<>
-
+
{showForm ? : }
{[...Array(25)].map((_, index) => (
diff --git a/src/pages/apply/components/ApplyForm.tsx b/src/pages/apply/components/ApplyForm.tsx
index 0043c91..8fce064 100644
--- a/src/pages/apply/components/ApplyForm.tsx
+++ b/src/pages/apply/components/ApplyForm.tsx
@@ -32,6 +32,7 @@ import {
} from '@gdsc/pages/apply/components/ApplyFormDocs';
import { ApplyFormSchema } from '@gdsc/utils/ApplyFormScehma.util';
+import { handleFormSubmit } from '@gdsc/utils/anlytics';
import { useApplyFormMutation } from '@gdsc/apis/hooks/apply/ApplyFormQuery';
@@ -141,10 +142,12 @@ const ApplyForm = () => {
})) || [],
};
if (submitType === 'submit') {
+ handleFormSubmit('Final Submit');
submitApplication(finalFormData);
// console.log(finalFormData);
} else if (submitType === 'save') {
// console.log(saveFormData);
+ handleFormSubmit('Save Submit');
submitApplication(saveFormData);
}
}
diff --git a/src/pages/apply/components/ApplySaveForm.tsx b/src/pages/apply/components/ApplySaveForm.tsx
index 8d51b60..9fca843 100644
--- a/src/pages/apply/components/ApplySaveForm.tsx
+++ b/src/pages/apply/components/ApplySaveForm.tsx
@@ -31,6 +31,7 @@ import {
} from '@gdsc/pages/apply/components/ApplyFormDocs';
import { ApplyFormSchema } from '@gdsc/utils/ApplyFormScehma.util';
+import { handleFormSubmit } from '@gdsc/utils/anlytics';
import { useApplySaveMutation } from '@gdsc/apis/hooks/apply/ApplySaveQuery';
@@ -45,8 +46,8 @@ import {
import {
ApplyFormInterface,
ApplyFormQuestionInterface,
+ ApplyFormAPIInterface,
} from '@gdsc/types/ApplyInterface';
-import { ApplyFormAPIInterface } from '@gdsc/types/ApplyInterface';
import { ErrorMessage } from '@hookform/error-message';
import { zodResolver } from '@hookform/resolvers/zod';
@@ -128,11 +129,13 @@ const ApplySaveForm = ({ SaveData }: ApplySaveFormProps) => {
})) || [],
};
if (submitType === 'submit') {
+ handleFormSubmit('Sub-Final Submit');
saveApplication(finalFormData);
// console.log(finalFormData);
} else if (submitType === 'save') {
// submitApplication(saveFormData);
// console.log(saveFormData);
+ handleFormSubmit('Sub-Save Submit');
saveApplication(saveFormData);
}
}
diff --git a/src/pages/community/CommunityPage.tsx b/src/pages/community/CommunityPage.tsx
index d109800..de20869 100644
--- a/src/pages/community/CommunityPage.tsx
+++ b/src/pages/community/CommunityPage.tsx
@@ -1,5 +1,13 @@
+import CommingSoonPage from '../CommingSoonPage';
+import { CommunityMetaData } from '@gdsc/router/components/MetaData';
+
const CommunityPage = () => {
- return <>커뮤니티 페이지>;
+ return (
+ <>
+
+
+ >
+ );
};
export default CommunityPage;
diff --git a/src/pages/introduce/IntroducePage.tsx b/src/pages/introduce/IntroducePage.tsx
index 50869e1..b5bf8d0 100644
--- a/src/pages/introduce/IntroducePage.tsx
+++ b/src/pages/introduce/IntroducePage.tsx
@@ -8,23 +8,21 @@ import FieldTable from '@gdsc/pages/introduce/components/FieldTable';
import IntroduceEvent from '@gdsc/pages/introduce/components/IntroduceEvent';
import LineEvent from '@gdsc/pages/introduce/components/LineEvent';
-import { SEO } from '@gdsc/utils/Seo';
+import useScrollTracker from '@gdsc/hooks/useScrollTracker';
import { DisplayLayout } from '@gdsc/styles/LayoutStyle';
+import { IntroduceMetaData } from '@gdsc/router/components/MetaData';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
const IntroducePage = () => {
+ useScrollTracker();
+
return (
<>
-
+
diff --git a/src/pages/main/MainPage.tsx b/src/pages/main/MainPage.tsx
index a128206..b48ff60 100644
--- a/src/pages/main/MainPage.tsx
+++ b/src/pages/main/MainPage.tsx
@@ -1,5 +1,4 @@
import { lazy } from 'react';
-import { Helmet } from 'react-helmet-async';
import { useMediaQuery } from 'react-responsive';
import Content from '@gdsc/pages/main/components/Content';
@@ -8,6 +7,7 @@ import MainRound from '@gdsc/pages/main/components/MainRound';
import { DisplayLayout } from '@gdsc/styles/LayoutStyle';
import styled from '@emotion/styled';
+import { MainMetaData } from '@gdsc/router/components/MetaData';
const MainFooterMobile = lazy(
() => import('@gdsc/components/feature/footer/MainFooterMobile')
@@ -29,20 +29,7 @@ const MainPage = () => {
return (
<>
-
- GDSC KNU - 메인 페이지
-
-
-
-
-
-
+
diff --git a/src/pages/main/components/RotateCarousel.style.ts b/src/pages/main/components/RotateCarousel.style.ts
index 25f248a..3e3684d 100644
--- a/src/pages/main/components/RotateCarousel.style.ts
+++ b/src/pages/main/components/RotateCarousel.style.ts
@@ -118,4 +118,4 @@ export const EarthVideo = styled.video`
left: 50%;
transform: translate(-50%, -50%);
clip-path: view-box ellipse(44% 44%);
-`;
\ No newline at end of file
+`;
diff --git a/src/pages/mypage/MyPage.tsx b/src/pages/mypage/MyPage.tsx
index 441a388..fc9be73 100644
--- a/src/pages/mypage/MyPage.tsx
+++ b/src/pages/mypage/MyPage.tsx
@@ -15,6 +15,7 @@ import { usePutMyData } from '@gdsc/apis/hooks/mypage/usePutMyData';
import { displayCenter } from '@gdsc/styles/LayoutStyle';
import styled from '@emotion/styled';
+import { MypageMetaData } from '@gdsc/router/components/MetaData';
import { putUserDataInterface } from '@gdsc/types/UserInterface';
const MyPageWrapper = styled.div<{ color: string }>`
@@ -199,6 +200,7 @@ const MyPage = () => {
return (
<>
+
diff --git a/src/pages/signin/SigninPage.tsx b/src/pages/signin/SigninPage.tsx
index 0c13866..51e9de2 100644
--- a/src/pages/signin/SigninPage.tsx
+++ b/src/pages/signin/SigninPage.tsx
@@ -2,7 +2,6 @@ import { useEffect } from 'react';
import SigninModal from '@gdsc/pages/signin/components/SigninModal';
-import { SEO } from '@gdsc/utils/Seo';
import { detectUserAgent } from '@gdsc/utils/detectUserAgent';
import {
openLinkInKakaoExternal,
@@ -11,6 +10,8 @@ import {
import { AuthWrapper } from '@gdsc/styles/AuthModalStyle';
+import { SigninMetaData } from '@gdsc/router/components/MetaData';
+
const SigninPage = () => {
useEffect(function RedirectByUserAgent() {
const signInUrl = 'https://gdsc-knu.com/signin';
@@ -23,12 +24,7 @@ const SigninPage = () => {
return (
<>
-
+
diff --git a/src/pages/signup/SignupPendingPage.tsx b/src/pages/signup/SignupPendingPage.tsx
index 9bd184c..502cb60 100644
--- a/src/pages/signup/SignupPendingPage.tsx
+++ b/src/pages/signup/SignupPendingPage.tsx
@@ -6,7 +6,6 @@ import homeIcon from '@gdsc/assets/HomeIcon.svg';
import { AuthWrapper, AuthBox } from '@gdsc/styles/AuthModalStyle';
import { displayCenter } from '@gdsc/styles/LayoutStyle';
-// eslint-disable-next-line import/no-unresolved
import logo from '/GDSC.svg';
import styled from '@emotion/styled';
diff --git a/src/pages/team/index.tsx b/src/pages/team/index.tsx
index 8b21b76..a52476b 100644
--- a/src/pages/team/index.tsx
+++ b/src/pages/team/index.tsx
@@ -1,3 +1,13 @@
-export const TeamPage = () => {
- return <>123>;
+import CommingSoonPage from '../CommingSoonPage';
+import { TeamMetaData } from '@gdsc/router/components/MetaData';
+
+const TeamPage = () => {
+ return (
+ <>
+
+
+ >
+ );
};
+
+export default TeamPage;
diff --git a/src/pages/tech_blog/TechBlogPage.tsx b/src/pages/tech_blog/TechBlogPage.tsx
index 0852176..517d6fe 100644
--- a/src/pages/tech_blog/TechBlogPage.tsx
+++ b/src/pages/tech_blog/TechBlogPage.tsx
@@ -1,5 +1,13 @@
+import CommingSoonPage from '../CommingSoonPage';
+import { TeamBlogMetaData } from '@gdsc/router/components/MetaData';
+
const TechBlogPage = () => {
- return <>테크블로그 페이지>;
+ return (
+ <>
+
+
+ >
+ );
};
export default TechBlogPage;
diff --git a/src/router/Router.tsx b/src/router/Router.tsx
index ee4047d..4acbad3 100644
--- a/src/router/Router.tsx
+++ b/src/router/Router.tsx
@@ -1,18 +1,22 @@
import { lazy } from 'react';
-import { createBrowserRouter } from 'react-router-dom';
+import {
+ createBrowserRouter,
+ IndexRouteObject,
+ NonIndexRouteObject,
+ Outlet,
+} from 'react-router-dom';
import { AsyncBoundary } from '@gdsc/components/common/AsyncBoundary';
import { LoadingView } from '@gdsc/components/common/View/LoadingView';
-// import { TeamPage } from '@gdsc/pages/team';
-// import TechBlogPage from '@gdsc/pages/tech_blog/TechBlogPage';
-import ErrorPage from '@gdsc/pages/ErrorPage';
-
-// import CommunityPage from '@gdsc/pages/community/CommunityPage';
import { TeamUpdateProvider } from '@gdsc/provider/TeamUpdate';
+import RouteChangeTracker from '@gdsc/router/components/RouteChangeTracker';
import StatusRoute from '@gdsc/router/components/StatusRoute';
-const CommingSoonPage = lazy(() => import('@gdsc/pages/CommingSoonPage'));
+const TechBlogPage = lazy(() => import('@gdsc/pages/tech_blog/TechBlogPage'));
+const ErrorPage = lazy(() => import('@gdsc/pages/ErrorPage'));
+const CommunityPage = lazy(() => import('@gdsc/pages/community/CommunityPage'));
+const TeamPage = lazy(() => import('@gdsc/pages/team'));
const RootPage = lazy(() => import('@gdsc/pages/RootPage'));
const MainPage = lazy(() => import('@gdsc/pages/main/MainPage'));
const SigninPage = lazy(() => import('@gdsc/pages/signin/SigninPage'));
@@ -37,32 +41,24 @@ const AdminTeamArrangePage = lazy(
() => import('@gdsc/pages/admin/AdminTeamArrangePage')
);
-export const Router = createBrowserRouter([
+type AppRouteObject = (IndexRouteObject | NonIndexRouteObject) & {
+ children?: AppRouteObject[];
+};
+
+const routesConfig: AppRouteObject[] = [
{
path: '/',
- element: (
- }>
-
-
- ),
+ element: ,
id: 'root',
errorElement: ,
children: [
{
index: true,
- element: (
- }>
-
-
- ),
+ element: ,
},
{
path: 'signin',
- element: (
- }>
-
-
- ),
+ element: ,
},
{
path: 'apply',
@@ -70,40 +66,25 @@ export const Router = createBrowserRouter([
children: [
{
path: '',
- element: (
- }>
-
-
- ),
+ element: ,
},
{
path: ':tech',
+ element: ,
children: [
{
path: '',
- element: (
- }>
-
-
- ),
+ element: ,
},
{
path: 'form',
- element: (
- }>
-
-
- ),
+ element: ,
},
],
},
{
path: 'inquiry',
- element: (
- }>
-
-
- ),
+ element: ,
},
],
},
@@ -113,11 +94,7 @@ export const Router = createBrowserRouter([
children: [
{
path: '',
- element: (
- }>
-
-
- ),
+ element: ,
},
],
},
@@ -127,21 +104,13 @@ export const Router = createBrowserRouter([
children: [
{
path: '',
- element: (
- }>
-
-
- ),
+ element: ,
},
],
},
{
path: 'introduce',
- element: (
- }>
-
-
- ),
+ element: ,
},
{
path: 'community',
@@ -149,11 +118,7 @@ export const Router = createBrowserRouter([
children: [
{
path: '',
- element: (
- }>
-
-
- ),
+ element: ,
},
],
},
@@ -163,11 +128,7 @@ export const Router = createBrowserRouter([
children: [
{
path: '',
- element: (
- }>
-
-
- ),
+ element: ,
},
],
},
@@ -175,11 +136,7 @@ export const Router = createBrowserRouter([
},
{
path: '/admin',
- element: (
- }>
-
-
- ),
+ element: ,
id: 'adminRoot',
errorElement: ,
children: [
@@ -189,11 +146,7 @@ export const Router = createBrowserRouter([
children: [
{
path: '',
- element: (
- }>
-
-
- ),
+ element: ,
},
],
},
@@ -204,11 +157,9 @@ export const Router = createBrowserRouter([
{
path: '',
element: (
- }>
-
-
-
-
+
+
+
),
},
],
@@ -219,11 +170,7 @@ export const Router = createBrowserRouter([
children: [
{
path: '',
- element: (
- }>
-
-
- ),
+ element: ,
},
],
},
@@ -231,18 +178,47 @@ export const Router = createBrowserRouter([
},
{
path: '/oauth/:provider/redirect',
- element: (
- }>
-
-
- ),
+ element: ,
},
{
path: 'signup',
- element: (
- }>
-
-
- ),
+ element: ,
},
-]);
+];
+
+const createRoutesWithAsyncBoundary = (
+ routes: AppRouteObject[]
+): AppRouteObject[] => {
+ return routes.map((route) => {
+ const { element, children, ...rest } = route;
+
+ if ('index' in route) {
+ return {
+ ...rest,
+ element: (
+ }>
+
+ {element}
+
+ ),
+ } as AppRouteObject;
+ } else {
+ return {
+ ...rest,
+ element: (
+ }>
+
+ {element}
+
+ ),
+ children: children
+ ? createRoutesWithAsyncBoundary(children)
+ : undefined,
+ } as AppRouteObject;
+ }
+ });
+};
+
+export const Router = createBrowserRouter(
+ createRoutesWithAsyncBoundary(routesConfig)
+);
diff --git a/src/router/components/MetaData.tsx b/src/router/components/MetaData.tsx
new file mode 100644
index 0000000..6e4a382
--- /dev/null
+++ b/src/router/components/MetaData.tsx
@@ -0,0 +1,128 @@
+import { useParams } from 'react-router-dom';
+
+import { SEO } from '@gdsc/router/components/Seo';
+
+export const MainMetaData = () => {
+ return (
+
+ );
+};
+
+export const SigninMetaData = () => {
+ return (
+
+ );
+};
+
+export const MypageMetaData = () => {
+ return (
+
+ );
+};
+
+export const IntroduceMetaData = () => {
+ return (
+
+ );
+};
+
+export const ApplyMetaData = () => {
+ return (
+
+ );
+};
+
+export const ApplyFormMetaData = () => {
+ const { tech } = useParams();
+
+ return (
+
+ );
+};
+
+export const ApplyExMetaData = () => {
+ const { tech } = useParams();
+
+ return (
+
+ );
+};
+
+export const ApplyInquiryMetaData = () => {
+ return (
+
+ );
+};
+
+export const TeamBlogMetaData = () => {
+ return (
+
+ );
+};
+
+export const TeamMetaData = () => {
+ return (
+
+ );
+};
+
+export const CommunityMetaData = () => {
+ return (
+
+ );
+};
diff --git a/src/utils/RouteChangeTracker.tsx b/src/router/components/RouteChangeTracker.ts
similarity index 66%
rename from src/utils/RouteChangeTracker.tsx
rename to src/router/components/RouteChangeTracker.ts
index 88bc32a..d2d1796 100644
--- a/src/utils/RouteChangeTracker.tsx
+++ b/src/router/components/RouteChangeTracker.ts
@@ -2,22 +2,25 @@ import { useEffect, useState } from 'react';
import ReactGA from 'react-ga4';
import { useLocation } from 'react-router-dom';
+import { trackPageView } from '@gdsc/utils/anlytics';
+
const RouteChangeTracker = () => {
const location = useLocation();
- const [initialized, setInitialized] = useState(false);
+ const [initialized, setInitialized] = useState(false);
useEffect(() => {
- if (!window.location.href.includes('localhost')) {
- ReactGA.initialize(import.meta.env.VITE_APP_GA_TRACKING_ID);
+ if (import.meta.env.VITE_ENV === 'production') {
+ ReactGA.initialize(import.meta.env.VITE_APP_GA_TRACKING_ID as string);
}
setInitialized(true);
}, []);
+
useEffect(() => {
if (initialized) {
- ReactGA.set({ page: location.pathname });
- ReactGA.send('pageview');
+ trackPageView(location.pathname);
}
}, [initialized, location]);
+
return null;
};
diff --git a/src/utils/Seo.tsx b/src/router/components/Seo.tsx
similarity index 73%
rename from src/utils/Seo.tsx
rename to src/router/components/Seo.tsx
index f3c7529..55de5f7 100644
--- a/src/utils/Seo.tsx
+++ b/src/router/components/Seo.tsx
@@ -16,7 +16,12 @@ export const SEO = ({ title, description, url, image }: SEOProps) => {
+
+
+
+
+
diff --git a/src/utils/anlytics.ts b/src/utils/anlytics.ts
new file mode 100644
index 0000000..d43701c
--- /dev/null
+++ b/src/utils/anlytics.ts
@@ -0,0 +1,35 @@
+import ReactGA from 'react-ga4';
+
+export const handleClickBtn = (label: string) => {
+ ReactGA.event({
+ category: 'Button',
+ action: 'Click',
+ label: label,
+ value: 1,
+ });
+};
+
+export const handleFormSubmit = (label: string) => {
+ ReactGA.event({
+ category: 'Form',
+ action: 'Submit',
+ label: label,
+ value: 1,
+ });
+};
+
+export const handleScroll = () => {
+ ReactGA.event({
+ category: 'Scroll',
+ action: 'User Scrolled',
+ label: 'Scrolled Down 50%',
+ value: 50,
+ });
+};
+
+export const trackPageView = (path: string) => {
+ if (import.meta.env.VITE_ENV === 'production') {
+ ReactGA.set({ page: path });
+ ReactGA.send('pageview');
+ }
+};
diff --git a/vite.config.ts b/vite.config.ts
index 953b98b..104c96b 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -13,7 +13,6 @@ export default defineConfig({
'/',
'/signin',
'/introduce',
- '/signup',
'/apply',
'/apply/inquiry',
'/apply/frontend',
@@ -26,6 +25,10 @@ export default defineConfig({
'/apply/android/form',
'/apply/designer',
'/apply/designer/form',
+ '/mypage',
+ '/team',
+ '/community',
+ '/techblog',
],
renderer: new PuppeteerRenderer({
maxConcurrentRoutes: 1,