Skip to content

Commit

Permalink
[feat] 인터랙션 확인 후 정답 컴포넌트 일부 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
darkdulgi committed Aug 8, 2024
1 parent 6e03263 commit 405c361
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 11 deletions.
5 changes: 5 additions & 0 deletions public/icons/left-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/icons/polygon-tri.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
98 changes: 98 additions & 0 deletions src/interactions/InteractionAnswer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import userStore from "@/auth/store.js";
import scrollTo from "@/scroll/scrollTo";
import style from "./InteractionAnswer.module.css";
import { useState } from "react";

export default function InteractionAnswer({
isAnswerUp,
setIsAnswerUp,
answer,
close,
}) {
const isLogin = userStore((state) => state.isLogin);
const [isAniPlaying, setIsAniPlaying] = useState(false);

function onClickWrite() {
close();
scrollTo(3);
}

function onClickShare() {
setIsAniPlaying(true);

/*
* 서버에서 받아온 단축 url을 클립보드에 복사하는 코드 미구현
*/
}

return (
<div
className={`top-0 ${isAnswerUp ? "" : "translate-y-full"} absolute w-full h-full flex items-center justify-center bg-black/90 transition-all ease-out duration-300`}
>
<span
onAnimationEnd={() => setIsAniPlaying(false)}
className={`${isAniPlaying ? style.toast : ""} opacity-0 fixed top-10 left-1/2 -translate-x-1/2 px-8 py-4 rounded-full bg-blue-100 text-neutral-600 text-body-m font-bold`}
>
단축 URL이 클립보드에 복사 되었습니다!
</span>

<button
onClick={() => setIsAnswerUp(false)}
className="absolute top-10 left-10 p-3 bg-neutral-800 rounded-full"
>
<img src="icons/left-arrow.svg" alt="뒤로가기" />
</button>

<div className="w-1/2 flex gap-8">
<span className="text-head-l text-blue-400 font-bold whitespace-pre">
{answer.head}
</span>
<div className="flex flex-col gap-4">
<span className="text-title-s text-neutral-50">{answer.desc}</span>

<span className="text-body-s text-neutral-300">{answer.subdesc}</span>
</div>
</div>

<div className="absolute bottom-10 flex flex-col items-center gap-10">
{isLogin ? (
<>
<span className="text-body-m text-green-400 font-bold">
오늘 응모가 완료되었습니다!
</span>

<div className="flex gap-4 items-end">
<div className="flex flex-col gap-2">
<div className="relative flex flex-col items-center animate-bounce">
<span className=" bg-green-400 text-nowrap text-body-m text-neutral-800 rounded-full px-8 py-2 font-bold">
당첨확률 UP!
</span>

<img src="icons/polygon-tri.svg" alt="역삼각형" />
</div>

<button
onClick={onClickWrite}
className="bg-white text-body-m text-black px-10 py-4"
>
기대평 작성하기
</button>
</div>

<button
onClick={onClickShare}
className="border-2 border-neutral-300 text-body-m text-white px-10 py-[14px]"
>
공유하기
</button>
</div>
</>
) : (
<button className="text-body-m text-black bg-white px-10 py-4">
응모하기
</button>
)}
</div>
</div>
);
}
18 changes: 18 additions & 0 deletions src/interactions/InteractionAnswer.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.toast {
animation: toast-ani 5s linear;
}

@keyframes toast-ani {
0% {
opacity: 0;
}
5% {
opacity: 1;
}
95% {
opacity: 1;
}
100% {
opacity: 0;
}
}
29 changes: 20 additions & 9 deletions src/interactions/InteractionModal.jsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import Suspense from "@/common/Suspense.jsx";
import { ModalCloseContext } from "@/modal/modal.jsx";
import { lazy, useContext, useRef, useState } from "react";
import InteractionAnswer from "./InteractionAnswer";

export default function InteractionModal({ index }) {
const lazyInteractionList = [
lazy(() => import("./distanceDriven")),
lazy(() => import("./fastCharge")),
lazy(() => import("./univasalIsland")),
lazy(() => import("./v2l")),
lazy(() => import("./subsidy")),
];
const lazyInteractionList = [
lazy(() => import("./distanceDriven")),
lazy(() => import("./fastCharge")),
lazy(() => import("./univasalIsland")),
lazy(() => import("./v2l")),
lazy(() => import("./subsidy")),
];

export default function InteractionModal({ index, answer }) {
const close = useContext(ModalCloseContext);
const InteractionComponent = lazyInteractionList[index];
const [isActive, setIsActive] = useState(false);
const [isAnswerUp, setIsAnswerUp] = useState(false);
const interactionRef = useRef(null);

if (!InteractionComponent) return <></>;

return (
<Suspense fallback={<div>Loading...</div>}>
<div className="w-5/6 h-5/6 relative backdrop-blur-[100px] border border-neutral-600 rounded">
<div className="w-5/6 h-5/6 relative backdrop-blur-[100px] border border-neutral-600 rounded overflow-hidden">
<button
onClick={close}
className="z-10 absolute top-10 right-10 bg-neutral-800 p-3 rounded-full"
Expand All @@ -34,6 +37,7 @@ export default function InteractionModal({ index }) {

<div className="absolute bottom-6 left-1/2 -translate-x-1/2 flex gap-4">
<button
onClick={() => setIsAnswerUp(true)}
disabled={!isActive}
className={`${isActive ? "opacity-100" : "opacity-50"} bg-white px-10 py-4 text-black text-body-s`}
>
Expand All @@ -47,6 +51,13 @@ export default function InteractionModal({ index }) {
<img src="icons/refresh.svg" alt="다시하기" />
</button>
</div>

<InteractionAnswer
isAnswerUp={isAnswerUp}
setIsAnswerUp={setIsAnswerUp}
answer={answer}
close={close}
/>
</div>
</Suspense>
);
Expand Down
6 changes: 5 additions & 1 deletion src/interactions/InteractionSlide.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default function InteractionSlide({
isCurrent,
joined,
swiperRef,
answer,
}) {
const activeImgPath = `active${index + 1}.png`;
const inactiveImgPath = `inactive${index + 1}.png`;
Expand All @@ -26,7 +27,10 @@ export default function InteractionSlide({
function onClickExperience() {
if (joined < 0) return;

openModal(<InteractionModal index={index}/>, "interaction");
openModal(
<InteractionModal index={index} answer={answer} />,
"interaction",
);
}

return (
Expand Down
2 changes: 1 addition & 1 deletion src/interactions/content.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"subdesc": "배터리 용량이 늘어났음에도 기존과 동일하거나 더 빠른 속도로 차량을 충전할 수 있습니다. 또한 다양한 EV 충전 솔루션과 충전 서비스를 통해 차별화된 충전 경험을 제공합니다."
},
{
"head": "Universal Island",
"head": "Universal\nIsland",
"desc": "더 뉴 아이오닉 5는 유니버설 아일랜드를 적용해 다양한 상황에 맞는 최적화된 공간 활용성을 제공합니다.",
"subdesc": "기존 모델과 달리 더 뉴 아이오닉 5에서는 자주 사용하는 기능을 버튼식으로 배치했으며, 스마트폰 무선 충전 패드도 상단으로 옮겨 사용 편의성을 높였습니다."
},
Expand Down
1 change: 1 addition & 0 deletions src/interactions/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default function InteractionPage() {
isCurrent={currentInteraction === index}
joined={joinedList[index]}
swiperRef={swiperRef}
answer={JSONData.answer[index]}
/>
</swiper-slide>
))}
Expand Down

0 comments on commit 405c361

Please sign in to comment.