diff --git a/service/package.json b/service/package.json
index 72e4bb0..a9fd602 100644
--- a/service/package.json
+++ b/service/package.json
@@ -21,6 +21,7 @@
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.5.1",
"framer-motion": "^11.3.28",
+ "js-confetti": "^0.12.0",
"json-server": "^1.0.0-beta.1",
"micro-slider": "^1.1.0",
"postcss": "^8.4.39",
diff --git a/service/src/App.jsx b/service/src/App.jsx
index 247f0f0..01fed5e 100644
--- a/service/src/App.jsx
+++ b/service/src/App.jsx
@@ -16,6 +16,7 @@ function App() {
/^\/event\/noQuiz$/,
/^\/event\/reward$/,
/^\/event\/comments\/commentId\/\d+$/,
+ /^\/event\/\w+$/,
];
const hideHeader = hideHeaderPattern.some(pattern =>
@@ -30,6 +31,7 @@ function App() {
/^\/event\/noQuiz$/,
/^\/event\/reward$/,
/^\/event\/comments\/commentId\/\d+$/,
+ /^\/event\/\w+$/,
];
const hideFooter = hideFooterPattern.some(pattern =>
diff --git a/service/src/assets/icons/Loading.svg b/service/src/assets/icons/Loading.svg
new file mode 100644
index 0000000..b04b312
--- /dev/null
+++ b/service/src/assets/icons/Loading.svg
@@ -0,0 +1,10 @@
+
diff --git a/service/src/components/modal/EventResultModal.jsx b/service/src/components/modal/EventResultModal.jsx
index 678b07a..ff1f367 100644
--- a/service/src/components/modal/EventResultModal.jsx
+++ b/service/src/components/modal/EventResultModal.jsx
@@ -1,6 +1,5 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
-
import ModalFrame from './ModalFrame';
import BlueButton from '@/components/buttons/BlueButton';
import BlueCheckIcon from '@/assets/icons/blueCheckIcon.svg';
@@ -26,7 +25,11 @@ function EventResultModal({ closeResultModal, data, handleSendPrize }) {
>
{data.isDrawWin ? (
-
+
{
- try {
- const response = await postReward();
- if (response && response.image) {
- const updatedUserInfo = { ...userInfo, toolBoxCnt: toolBoxCnt - 1 };
- setUserInfo(updatedUserInfo);
- navigate(`/event/reward`, { state: response });
- } else {
- console.log('유효하지 않은 응답입니다: ', response);
- }
- } catch (error) {
- console.error(error);
- }
+ navigate(`/event/reward`);
};
return (
diff --git a/service/src/pages/joinEvent/Reward.jsx b/service/src/pages/joinEvent/Reward.jsx
index f4b6c9d..0853991 100644
--- a/service/src/pages/joinEvent/Reward.jsx
+++ b/service/src/pages/joinEvent/Reward.jsx
@@ -1,15 +1,63 @@
-import React, { useState } from 'react';
+import React, { useState, useEffect, useContext } from 'react';
import EventResultModal from '@/components/modal/EventResultModal';
import PrizeLinkSentModal from '@/components/modal/PrizeLinkSentModal';
-import { useNavigate, useLocation } from 'react-router-dom';
-import { postSendPrize } from '@/api/rapple/index';
+import { useNavigate } from 'react-router-dom';
+import { postReward, postSendPrize } from '@/api/rapple/index';
+import { AuthContext } from '@/context/authContext';
+import Loading from '@/assets/icons/Loading.svg';
+import BlueButton from '@/components/buttons/BlueButton';
+import JSConfetti from 'js-confetti';
function Reward() {
const navigate = useNavigate();
- const [openResultModal, setOpenResultModal] = useState(true);
+ const [openResultModal, setOpenResultModal] = useState(false);
const [openMessageModal, setOpenMessageModal] = useState(false);
const [resultImage, setResultImage] = useState('');
- const data = useLocation().state;
+ const { userInfo, setUserInfo } = useContext(AuthContext);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(false);
+ const [data, setData] = useState({});
+ const { toolBoxCnt } = userInfo;
+
+ useEffect(() => {
+ const confetti = new JSConfetti();
+
+ const timer = setTimeout(() => {
+ handleReward(confetti);
+ }, 1500);
+
+ return () => clearTimeout(timer);
+ }, []);
+
+ const handleReward = async confetti => {
+ if (userInfo.toolBoxCnt > 0) {
+ try {
+ const response = await postReward();
+ console.log(response);
+ if (response && response.image) {
+ setData(response);
+ const updatedUserInfo = { ...userInfo, toolBoxCnt: toolBoxCnt - 1 };
+ setUserInfo(updatedUserInfo);
+ setLoading(false);
+ setOpenResultModal(true);
+ if (response.isDrawWin && confetti) {
+ confetti.addConfetti({
+ confettiColors: ['#CAB0FF'],
+ confettiNumber: 500,
+ });
+ }
+ } else {
+ console.log('유효하지 않은 응답입니다: ', response);
+ setError(true);
+ }
+ } catch (error) {
+ console.error(error);
+ setError(true);
+ }
+ } else {
+ setError(true);
+ }
+ };
const closeResultModal = () => {
setOpenResultModal(false);
@@ -26,8 +74,44 @@ function Reward() {
}
};
+ const goToEventPage = () => {
+ navigate('/event');
+ };
+
+ if (error) {
+ return (
+
+
+ 예상하지 못한 에러가 발생했습니다..!
+
+
+
+ );
+ }
+
return (
+ {loading && !error && (
+
+
+
+
+ 경품을 응모중입니다.
+
+
+ 잠시만 기다려주세요.
+
+
+
+ )}
{openResultModal && (
{
setOpenCommentModal(false);
@@ -69,6 +71,7 @@ function CommentDetail() {
setComment(response);
setIsLiked(response.isLiked);
setLikeCount(response.likeCount);
+ setLoading(false);
} catch (error) {
console.error('Failed to fetch comment detail:', error);
}
@@ -82,8 +85,13 @@ function CommentDetail() {
fetchComment();
}, [userInfo]);
- if (!comment) {
- return Loading...
;
+ if (loading) {
+ console.log('ddd');
+ return (
+
+
+
+ );
}
return (
diff --git a/service/src/pages/joinEvent/commentList/Redirect.jsx b/service/src/pages/joinEvent/commentList/Redirect.jsx
index 0555c08..454551e 100644
--- a/service/src/pages/joinEvent/commentList/Redirect.jsx
+++ b/service/src/pages/joinEvent/commentList/Redirect.jsx
@@ -1,6 +1,7 @@
-import { useEffect } from 'react';
+import React, { useEffect } from 'react';
import { getRedirectLink } from '@/api/comment/index';
import { useParams, useNavigate } from 'react-router-dom';
+import Loading from '@/assets/icons/Loading.svg';
function Redirect() {
const navigate = useNavigate();
@@ -13,6 +14,12 @@ function Redirect() {
useEffect(() => {
getLink();
}, []);
+
+ return (
+
+
+
+ );
}
export default Redirect;
diff --git a/service/src/styles/global.css b/service/src/styles/global.css
index 1081974..3e0b369 100644
--- a/service/src/styles/global.css
+++ b/service/src/styles/global.css
@@ -27,3 +27,16 @@
transition: transform 1s;
transform: rotate(180deg);
}
+
+.rotate-360 {
+ animation: spin 2s linear infinite;
+}
+
+@keyframes spin {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+}
diff --git a/service/yarn.lock b/service/yarn.lock
index 20705d1..f4603d3 100644
--- a/service/yarn.lock
+++ b/service/yarn.lock
@@ -4032,6 +4032,11 @@ jiti@^1.21.0:
resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz"
integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==
+js-confetti@^0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/js-confetti/-/js-confetti-0.12.0.tgz#5ed74dc6f430c0137115f350b2e3f1f119840157"
+ integrity sha512-1R0Akxn3Zn82pMqW65N1V2NwKkZJ75bvBN/VAb36Ya0YHwbaSiAJZVRr/19HBxH/O8x2x01UFAbYI18VqlDN6g==
+
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"