diff --git a/package-lock.json b/package-lock.json
index dfa1ecb..9359bc8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.26.1",
+ "react-toastify": "^10.0.5",
"react-transition-group": "^4.4.5",
"zustand": "^4.5.5"
},
@@ -5611,6 +5612,15 @@
"node": ">=12"
}
},
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -11384,6 +11394,19 @@
"react-dom": ">=16.8"
}
},
+ "node_modules/react-toastify": {
+ "version": "10.0.5",
+ "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz",
+ "integrity": "sha512-mNKt2jBXJg4O7pSdbNUfDdTsK9FIdikfsIE/yUCxbAEXl4HMyJaivrVFcn3Elvt5xvCQYhUZm+hqTIu1UXM3Pw==",
+ "license": "MIT",
+ "dependencies": {
+ "clsx": "^2.1.0"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-dom": ">=18"
+ }
+ },
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
diff --git a/package.json b/package.json
index aa04d39..d50d20e 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.26.1",
+ "react-toastify": "^10.0.5",
"react-transition-group": "^4.4.5",
"zustand": "^4.5.5"
},
diff --git a/src/App.tsx b/src/App.tsx
index 8cb7ab2..cb2df19 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,4 +1,6 @@
import { BrowserRouter } from "react-router-dom";
+import { Bounce, ToastContainer } from "react-toastify";
+import "react-toastify/dist/ReactToastify.css";
import { FontsStyle } from "@/styles/fonts";
import { GlobalStyle } from "@/styles/global";
@@ -9,6 +11,19 @@ import { Global } from "@emotion/react";
export default function App() {
return (
+
diff --git a/src/hooks/useRatioResult.tsx b/src/hooks/useRatioResult.tsx
new file mode 100644
index 0000000..d184d96
--- /dev/null
+++ b/src/hooks/useRatioResult.tsx
@@ -0,0 +1,32 @@
+import { useEffect, useState } from "react";
+import { useSearchParams } from "react-router-dom";
+
+import { api } from "@/config/axios";
+
+interface RatioResultResponse {
+ status: number;
+ count: number;
+ total_count: number;
+}
+
+export const useRatioResult = () => {
+ const [searchParams] = useSearchParams();
+
+ const [isPending, setIsPending] = useState(false);
+ const [totalCount, setTotalCount] = useState(0);
+ const [mbtiCount, setMbtiCount] = useState(0);
+
+ useEffect(() => {
+ setIsPending(true);
+ api.get(`/stats?type=${searchParams.get("type")}`)
+ .then((data) => {
+ setMbtiCount(data.data.count);
+ setTotalCount(data.data.total_count);
+ })
+ .finally(() => {
+ setIsPending(false);
+ });
+ }, []);
+
+ return { isPending, totalCount, mbtiCount };
+};
diff --git a/src/pages/AnalyticsPage.style.ts b/src/pages/AnalyticsPage.style.ts
index de24ea4..acecf63 100644
--- a/src/pages/AnalyticsPage.style.ts
+++ b/src/pages/AnalyticsPage.style.ts
@@ -1,5 +1,12 @@
import styled from "@emotion/styled";
+export const AnalyticsPageWrapper = styled.div`
+ width: 100%;
+ height: 100%;
+
+ margin-top: 60px;
+`;
+
export const TitleContainer = styled.div`
display: flex;
flex-direction: column;
diff --git a/src/pages/AnalyticsPage.tsx b/src/pages/AnalyticsPage.tsx
index 9c41d81..3a4b7be 100644
--- a/src/pages/AnalyticsPage.tsx
+++ b/src/pages/AnalyticsPage.tsx
@@ -4,6 +4,7 @@ import { useNavigate } from "react-router-dom";
import Footer from "@/components/display/Footer";
import DropDown from "@/components/form/DropDown";
import TopBar from "@/components/layout/TopBar";
+import { TopBarContainer, TopBarWrapper } from "@/components/layout/TopBar.styled";
import { Text } from "@/components/typography";
import { useTop10 } from "@/hooks/useTop10";
@@ -13,7 +14,17 @@ import backIcon from "@/assets/back.svg";
import { results } from "@/constants/results";
-import { TitleContainer, TitleTop, Main, MiddleSection, TableContainer, Card, Rank, Type } from "./AnalyticsPage.style";
+import {
+ TitleContainer,
+ TitleTop,
+ Main,
+ MiddleSection,
+ TableContainer,
+ Card,
+ Rank,
+ Type,
+ AnalyticsPageWrapper,
+} from "./AnalyticsPage.style";
export interface top10Response {
top: [string, number][];
@@ -67,10 +78,18 @@ export default function AnalyticsPage() {
}, [selectedDepartment]);
return (
- <>
-
+
+
+
+
+
+ 전체 통계
+
+
+
+
어떤 유형이 가장 많을까요?
@@ -103,6 +122,6 @@ export default function AnalyticsPage() {
{selectedDepartment && renderData(top10ByDepartment, top10ByDepartmentLoading, top10ByDepartmentError)}
- >
+
);
}
diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx
index c29dee2..00f06da 100644
--- a/src/pages/HomePage.tsx
+++ b/src/pages/HomePage.tsx
@@ -1,5 +1,6 @@
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
+import { toast } from "react-toastify";
import Footer from "@/components/display/Footer";
import { Button } from "@/components/form/Button";
@@ -29,8 +30,7 @@ export default function HomePage() {
const { isPending, isError, totalCount } = useTotalCount();
const navigate = useNavigate();
- const setName = useUserInfo((state) => state.setName);
- const setMajor = useUserInfo((state) => state.setMajor);
+ const userInfo = useUserInfo((state) => state);
const [isOpen, setIsOpen] = useState(false);
const [selectedMajor, setSelectedMajor] = useState("");
@@ -39,9 +39,21 @@ export default function HomePage() {
setIsOpen(!isOpen);
};
+ const handleStart = () => {
+ if (!userInfo.name) {
+ toast.error("이름을 입력해주세용");
+ return;
+ }
+ if (!userInfo.major) {
+ toast.error("단과대학을 입력해주세용");
+ return;
+ }
+ navigate("/select");
+ };
+
useEffect(() => {
- setMajor(selectedMajor);
- }, [selectedMajor, setMajor]);
+ userInfo.setMajor(selectedMajor);
+ }, [selectedMajor, userInfo.setMajor]);
return (
@@ -85,7 +97,7 @@ export default function HomePage() {
width="242px"
height="40px"
placeholder="이름을 입력하세용"
- onChange={(e) => setName(e.currentTarget.value)}
+ onChange={(e) => userInfo.setName(e.currentTarget.value)}
/>
navigate("/select")}
+ onClick={handleStart}
/>
diff --git a/src/pages/ResultPage.tsx b/src/pages/ResultPage.tsx
index 4bc9d73..0ca5c55 100644
--- a/src/pages/ResultPage.tsx
+++ b/src/pages/ResultPage.tsx
@@ -2,6 +2,7 @@ import { Button } from "@/components/form/Button";
import TopBar from "@/components/layout/TopBar";
import { Text } from "@/components/typography";
+import { useRatioResult } from "@/hooks/useRatioResult";
import { useResult } from "@/hooks/useResult";
import clubs from "@/constants/clubs";
@@ -24,6 +25,8 @@ import { css } from "@emotion/react";
export default function ResultPage() {
const { name, mbti, result, navigate } = useResult();
+ const { isPending, totalCount, mbtiCount } = useRatioResult();
+
return (
<>
@@ -78,7 +81,11 @@ export default function ResultPage() {
- 3,800명의 참가자 중 38명이 이 유형이 나왔어요!
+ {!isPending && (
+ <>
+ {totalCount}명의 참가자 중 {mbtiCount}명이 이 유형이 나왔어요!
+ >
+ )}