-
+
[제목]
diff --git a/projects/admin/src/PageContainer/ScoringPage/index.tsx b/projects/admin/src/PageContainer/ScoringPage/index.tsx
index 7d49e8da..96d2dd2e 100644
--- a/projects/admin/src/PageContainer/ScoringPage/index.tsx
+++ b/projects/admin/src/PageContainer/ScoringPage/index.tsx
@@ -1,14 +1,23 @@
'use client';
+import { useGetScoringList } from 'api/admin';
import * as S from './style';
import { MissionCarousel } from 'admin/components';
-const ScoringPage = () => (
-
- 채점하기
-
-
-);
+const ScoringPage = () => {
+ const { data } = useGetScoringList();
+
+ return (
+
+ 채점하기
+ {data?.length > 0 ? (
+
+ ) : (
+ 채점할 문제가 없습니다...
+ )}
+
+ );
+};
export default ScoringPage;
diff --git a/projects/admin/src/components/Timer/index.tsx b/projects/admin/src/components/Timer/index.tsx
index 7a945919..1ccdbe44 100644
--- a/projects/admin/src/components/Timer/index.tsx
+++ b/projects/admin/src/components/Timer/index.tsx
@@ -1,39 +1,41 @@
'use client';
import * as S from './style';
-import { Dispatch, SetStateAction, useState } from 'react';
+import { Dispatch, SetStateAction } from 'react';
interface TimerProps {
- time: number;
- setTime: Dispatch
>;
+ minute: number;
+ setMinute: Dispatch>;
+ second: number;
+ setSecond: Dispatch>;
}
-const Timer: React.FC = ({ time, setTime }) => {
- const [minute, setMinute] = useState(0);
- const [second, setSecond] = useState(0);
-
- const onMinuteChange = (e: React.ChangeEvent) => {
- const newMinute = parseInt(e.target.value) * 60;
- setMinute(newMinute);
- setTime(newMinute + second);
- };
-
- const onSecondChange = (e: React.ChangeEvent) => {
- const newSecond = parseInt(e.target.value);
- setSecond(newSecond);
- setTime(minute + newSecond);
- };
-
- return (
-
-
-
- :
-
-
- * 문제는 12:30 ~ 19:30분까지 풀 수 있습니다.
-
- );
-};
+const Timer: React.FC = ({
+ minute,
+ setMinute,
+ second,
+ setSecond,
+}) => (
+
+
+
+ e.target.value ? setMinute(parseInt(e.target.value)) : setMinute(0)
+ }
+ />
+ :
+
+ e.target.value ? setSecond(parseInt(e.target.value)) : setSecond(0)
+ }
+ />
+
+ * 문제는 12:30 ~ 19:30분까지 풀 수 있습니다.
+
+);
export default Timer;
diff --git a/projects/admin/tsconfig.json b/projects/admin/tsconfig.json
index e70cd06d..ddad5803 100644
--- a/projects/admin/tsconfig.json
+++ b/projects/admin/tsconfig.json
@@ -3,11 +3,25 @@
"compilerOptions": {
"jsx": "preserve",
"paths": {
- "common/*": ["../../packages/common/src/*"],
- "admin/*": ["./src/*"],
- "api/*": ["../../packages/api/*"]
- }
+ "common/*": [
+ "../../packages/common/src/*"
+ ],
+ "admin/*": [
+ "./src/*"
+ ],
+ "api/*": [
+ "../../packages/api/*"
+ ]
+ },
+ "strict": false
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
- "exclude": ["node_modules"]
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
}
diff --git a/projects/client/next.config.js b/projects/client/next.config.js
index f8bd7b31..e00614b0 100644
--- a/projects/client/next.config.js
+++ b/projects/client/next.config.js
@@ -1,6 +1,5 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
- reactStrictMode: true,
swcMinify: true,
transpilePackages: ['common', 'api'],
diff --git a/projects/client/src/PageContainer/MissionDetailPage/index.tsx b/projects/client/src/PageContainer/MissionDetailPage/index.tsx
index 6884aa66..3a9a33bf 100644
--- a/projects/client/src/PageContainer/MissionDetailPage/index.tsx
+++ b/projects/client/src/PageContainer/MissionDetailPage/index.tsx
@@ -38,6 +38,8 @@ const MissionDetailPage: React.FC = ({ missionId }) => {
};
useEffect(() => {
+ toast.error('문제를 푸는 동안에는 다른 페이지로 이동할 수 없습니다.');
+
const handleBeforeUnload = () =>
window.addEventListener('beforeunload', preventClose);
handleBeforeUnload();
@@ -57,7 +59,8 @@ const MissionDetailPage: React.FC = ({ missionId }) => {
const submitSolution = () => {
mutate({
- solvation: inputValue,
+ solvation:
+ inputValue.length > 0 ? inputValue : '시간초과로 제출된 사용자입니다.',
});
};
diff --git a/projects/client/src/app/layout.tsx b/projects/client/src/app/layout.tsx
index da5d4524..c9490799 100644
--- a/projects/client/src/app/layout.tsx
+++ b/projects/client/src/app/layout.tsx
@@ -5,6 +5,10 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { GlobalStyle } from 'common';
import { Header } from 'common';
+import Script from 'next/script';
+
+import * as gtag from 'client/libs/gtag';
+
import Providers from './providers';
export const metadata: Metadata = {
@@ -35,7 +39,7 @@ export const metadata: Metadata = {
openGraph: {
title: 'StackKnowledge',
description: '학습 장려 게임화 플랫폼입니다.',
- url: 'https://stack-knowledge-client.vercel.app/',
+ url: 'https://stackknowledge.vercel.app/',
siteName: 'StackKnowledge',
images: [
{
@@ -58,6 +62,27 @@ export default function RootLayout({
}) {
return (
+
+ {/* Global Site Tag (gtag.js) - Google Analytics */}
+
+
+
diff --git a/projects/client/src/app/mission/list/page.tsx b/projects/client/src/app/mission/list/page.tsx
index 86090d93..49f2e48b 100644
--- a/projects/client/src/app/mission/list/page.tsx
+++ b/projects/client/src/app/mission/list/page.tsx
@@ -8,7 +8,7 @@ export const metadata: Metadata = {
openGraph: {
title: '문제 목록',
description: 'StackKnowledge 문제 목록 페이지입니다.',
- url: 'https://stack-knowledge-client.vercel.app/mission/list/',
+ url: 'https://stackknowledge.vercel.app/mission/list/',
},
};
diff --git a/projects/client/src/app/mission/resolve/[missionId]/page.tsx b/projects/client/src/app/mission/resolve/[missionId]/page.tsx
index 55b64826..f947aefb 100644
--- a/projects/client/src/app/mission/resolve/[missionId]/page.tsx
+++ b/projects/client/src/app/mission/resolve/[missionId]/page.tsx
@@ -17,7 +17,7 @@ export const generateMetadata = async ({
openGraph: {
title: '문제 풀이',
description: 'StackKnowledge 문제 풀이 페이지입니다.',
- url: `https://stack-knowledge-client.vercel.app/mission/resolve/${missionId}`,
+ url: `https://stackknowledge.vercel.app/mission/resolve/${missionId}`,
},
};
};
diff --git a/projects/client/src/app/ranking/page.tsx b/projects/client/src/app/ranking/page.tsx
index a36dfd2d..02e765a4 100644
--- a/projects/client/src/app/ranking/page.tsx
+++ b/projects/client/src/app/ranking/page.tsx
@@ -8,7 +8,7 @@ export const metadata: Metadata = {
openGraph: {
title: '랭킹',
description: 'StackKnowledge 랭킹 페이지입니다.',
- url: 'https://stack-knowledge-client.vercel.app/ranking/',
+ url: 'https://stackknowledge.vercel.app/ranking/',
},
};
diff --git a/projects/client/src/app/shop/page.tsx b/projects/client/src/app/shop/page.tsx
index 9da395ba..8e40d903 100644
--- a/projects/client/src/app/shop/page.tsx
+++ b/projects/client/src/app/shop/page.tsx
@@ -8,7 +8,7 @@ export const metadata: Metadata = {
openGraph: {
title: '상점',
description: 'StackKnowledge 상점 페이지입니다.',
- url: 'https://stack-knowledge-client.vercel.app/shop/',
+ url: 'https://stackknowledge.vercel.app/shop/',
},
};
diff --git a/projects/client/src/components/ShopModal/index.tsx b/projects/client/src/components/ShopModal/index.tsx
index d4adfb26..58d1dee1 100644
--- a/projects/client/src/components/ShopModal/index.tsx
+++ b/projects/client/src/components/ShopModal/index.tsx
@@ -65,21 +65,27 @@ const ShopModal: React.FC = ({ selectedList }) => {
- 선택하신 상품이 맞으십니까?
-
- {selectedList?.map((selectedItem, index) => (
-
- ))}
-
-
+ {selectedList.length > 0 ? (
+ <>
+ 선택하신 상품이 맞습니까?
+
+ {selectedList?.map((selectedItem, index) => (
+
+ ))}
+
+
+ >
+ ) : (
+ 선택하신 상품이 없습니다...
+ )}
);
};
diff --git a/projects/client/src/libs/gtag.ts b/projects/client/src/libs/gtag.ts
new file mode 100644
index 00000000..e8080c46
--- /dev/null
+++ b/projects/client/src/libs/gtag.ts
@@ -0,0 +1,21 @@
+export const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GA_ID;
+
+// https://developers.google.com/analytics/devguides/collection/gtagjs/events
+export const event = (
+ action: Gtag.EventNames,
+ { event_category, event_label, value }: Gtag.EventParams
+) => {
+ window.gtag('event', action, {
+ event_category,
+ event_label,
+ value,
+ });
+};
+
+// https://developers.google.com/analytics/devguides/collection/gtagjs/pages
+export const pageview = (url: URL) => {
+ if (GA_TRACKING_ID)
+ window.gtag('config', GA_TRACKING_ID, {
+ page_path: url,
+ });
+};
diff --git a/projects/client/tsconfig.json b/projects/client/tsconfig.json
index 1dfa473b..1320e874 100644
--- a/projects/client/tsconfig.json
+++ b/projects/client/tsconfig.json
@@ -2,11 +2,13 @@
"extends": "tsconfig/nextjs.json",
"compilerOptions": {
"jsx": "preserve",
+ "types": ["@types/gtag.js"],
"paths": {
"common/*": ["../../packages/common/src/*"],
"client/*": ["./src/*"],
"api/*": ["../../packages/api/*"]
- }
+ },
+ "strict": false
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]