Skip to content

Commit

Permalink
Merge pull request #664 from sparcs-kaist/#622.1-event-store-randombox
Browse files Browse the repository at this point in the history
#622.1 랜덤박스 구매 인터렉션
  • Loading branch information
14KGun authored Sep 23, 2023
2 parents 8fe18dc + 2549b8d commit 3a59cf1
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 45 deletions.
4 changes: 4 additions & 0 deletions src/components/Event/BodyRandomBox/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@

.c2023fallevent-emoji {
position: absolute;
width: 500px;
height: 500px;
border-radius: 8px;
overflow: hidden;
font-size: 250px;
transform: rotateX(-25deg) rotateY(-25deg) translate(calc(250px - 50%), 0rem);
}
Expand Down
15 changes: 14 additions & 1 deletion src/components/Event/BodyRandomBox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ const BodyRandomBox = ({
}
`} 2s linear infinite;
`;
const styleItem = {
position: "absolute" as const,
top: "10%",
left: "10%",
width: "80%",
height: "80%",
};

return (
<div ref={bodyRef} css={{ height: `${boxSize * 1.3}px` }}>
Expand Down Expand Up @@ -96,7 +103,13 @@ const BodyRandomBox = ({
<TopPlane css={stylePlane} />
</div>
<div className="c2023fallevent-randombox-side c2023fallevent-randombox-side-bottom" />
<div className="c2023fallevent-emoji">🎟</div>
<div className="c2023fallevent-emoji">
{itemImageUrl ? (
<img src={itemImageUrl} alt="item" css={styleItem} />
) : (
"🎟"
)}
</div>
</div>
</div>
</div>
Expand Down
65 changes: 33 additions & 32 deletions src/components/ModalPopup/ModalEvent2023FallItem.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import { Dispatch, SetStateAction, useCallback, useMemo, useRef } from "react";

import type { EventItem } from "types/event2023fall";

import { useDelayBoolean } from "hooks/useDelay";
import {
useFetchRecoilState,
useValueRecoilState,
Expand All @@ -25,39 +26,48 @@ import { ReactComponent as CreditIcon } from "static/events/2023fallCredit.svg";
type ModalEvent2023FallItemProps = Parameters<typeof Modal>[0] & {
itemInfo: EventItem;
fetchItems?: () => void;
setRewardItem?: Dispatch<SetStateAction<Nullable<EventItem>>>;
};

const ModalEvent2023FallItem = ({
itemInfo,
fetchItems,
setRewardItem,
...modalProps
}: ModalEvent2023FallItemProps) => {
const fetchEvent2023FallInfo = useFetchRecoilState("event2023FallInfo");
const event2023FallInfo = useValueRecoilState("event2023FallInfo");

const axios = useAxios();
const setAlert = useSetRecoilState(alertAtom);
const isDisplayRandomBox = !useDelayBoolean(!modalProps.isOpen, 500);
const isRequesting = useRef<boolean>(false);

const onClickOk = useCallback(
() =>
axios({
url: `/events/2023fall/items/purchase/${itemInfo._id}`,
method: "post",
onSuccess: () => {
fetchEvent2023FallInfo();
fetchItems?.();
modalProps.onChangeIsOpen?.(false);
const onClickOk = useCallback(async () => {
if (isRequesting.current) return;
isRequesting.current = true;
await axios({
url: `/events/2023fall/items/purchase/${itemInfo._id}`,
method: "post",
onSuccess: ({ reward }) => {
fetchEvent2023FallInfo();
fetchItems?.();
modalProps.onChangeIsOpen?.(false);
if (itemInfo.itemType === 3 && reward) {
setRewardItem?.(reward);
} else {
setAlert("구매가 완료되었습니다. 구매 이력에서 확인보세요.");
},
onError: () => setAlert("구매를 실패하였습니다."),
}),
[
itemInfo._id,
fetchItems,
modalProps.onChangeIsOpen,
fetchEvent2023FallInfo,
]
);
}
},
onError: () => setAlert("구매를 실패하였습니다."),
});
isRequesting.current = false;
}, [
itemInfo._id,
fetchItems,
modalProps.onChangeIsOpen,
fetchEvent2023FallInfo,
]);

const [isDisabled, buttonText] = useMemo(
() =>
Expand All @@ -73,17 +83,6 @@ const ModalEvent2023FallItem = ({
[eventMode, event2023FallInfo, itemInfo]
);

const [isDisplayRandomBox, setIsDisplayRandomBox] = useState<boolean>(false);
useEffect(() => {
if (modalProps.isOpen) {
const timeout = setTimeout(() => {
setIsDisplayRandomBox(true);
}, 500);
return () => clearTimeout(timeout);
}
setIsDisplayRandomBox(false);
}, [modalProps.isOpen]);

const styleTitle = {
...theme.font18,
display: "flex",
Expand All @@ -105,7 +104,9 @@ const ModalEvent2023FallItem = ({
isDisplayRandomBox ? (
<BodyRandomBox isBoxOpend={false} />
) : (
<Loading />
<div css={{ textAlign: "center" }}>
<Loading />
</div>
)
) : (
<img
Expand Down
61 changes: 50 additions & 11 deletions src/components/ModalPopup/ModalEvent2023FallRandomBox.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { useCallback, useState } from "react";
import { memo, useCallback, useEffect, useState } from "react";

import type { EventItem } from "types/event2023fall";

import { useDelay, useDelayBoolean } from "hooks/useDelay";

import Button from "components/Button";
import DottedLine from "components/DottedLine";
import BodyRandomBox from "components/Event/BodyRandomBox";
import Loading from "components/Loading";
import Modal from "components/Modal";

import "./ModalEvent2023FallRandomBoxBackground.css";

import theme from "tools/theme";

import LocalAtmRoundedIcon from "@mui/icons-material/LocalAtmRounded";
import HelpCenterRoundedIcon from "@mui/icons-material/HelpCenterRounded";

const Background = () => (
<div css={{ position: "absolute", top: "20%", left: 0, bottom: 0, right: 0 }}>
Expand All @@ -18,14 +23,23 @@ const Background = () => (
</div>
);

type ModalEvent2023FallRandomBoxProps = Parameters<typeof Modal>[0] & {};
type ModalEvent2023FallRandomBoxProps = { item?: EventItem } & Parameters<
typeof Modal
>[0];

const ModalEvent2023FallRandomBox = ({
item,
...modalProps
}: ModalEvent2023FallRandomBoxProps) => {
const [isBoxOpend, setIsBoxOpend] = useState<boolean>(false);
const isDisplayRandomBox = !useDelayBoolean(!modalProps.isOpen, 500);
const isDisplayItemName = useDelay<boolean>(isBoxOpend, !isBoxOpend, 6000);
const onClickOk = useCallback(() => setIsBoxOpend(true), []);

useEffect(() => {
if (!modalProps.isOpen) setIsBoxOpend(false);
}, [modalProps.isOpen]);

const styleTitle = {
...theme.font18,
display: "flex",
Expand All @@ -50,29 +64,54 @@ const ModalEvent2023FallRandomBox = ({
{...modalProps}
>
<div css={styleTitle}>
<LocalAtmRoundedIcon style={styleIcon} />
<HelpCenterRoundedIcon style={styleIcon} />
랜덤박스 열기
</div>
<div css={styleText}>
랜덤박스를 획득했다. <b>상자</b> 또는 <b>열기</b> 버튼을 눌러 상자 안
상품을 확인해보자.
<b css={{ color: theme.purple }}>랜덤박스를 획득했어요.</b> <b>상자</b>{" "}
또는 <b>열기</b> 버튼을 눌러 상자 안 상품을 확인해세요!
</div>
<DottedLine />
<BodyRandomBox isBoxOpend={isBoxOpend} onClickBox={onClickOk} />
{isDisplayRandomBox ? (
<BodyRandomBox
itemImageUrl={item?.imageUrl}
isBoxOpend={isBoxOpend}
onClickBox={onClickOk}
/>
) : (
<div css={{ textAlign: "center" }}>
<Loading />
</div>
)}
{isDisplayItemName && (
<div css={styleText}>
축하합니다! 랜덤박스에서{" "}
<b>
{'"'}
{item?.name || ""}
{'"'}
</b>
을(를) 획득하였습니다
</div>
)}
<Button
type="purple_inset"
css={{
padding: "10px 0 9px",
borderRadius: "8px",
...theme.font14_bold,
}}
disabled={isBoxOpend}
onClick={onClickOk}
disabled={isDisplayItemName ? false : isBoxOpend}
onClick={
isDisplayItemName
? () => modalProps?.onChangeIsOpen?.(false)
: onClickOk
}
>
박스 열기
{isDisplayItemName ? "확인" : "박스 열기"}
</Button>
</Modal>
);
};

export default ModalEvent2023FallRandomBox;
export default memo(ModalEvent2023FallRandomBox);
14 changes: 13 additions & 1 deletion src/pages/Event/Event2023FallStore/ItemListSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import { useState } from "react";
import type { EventItem } from "types/event2023fall";

import Empty from "components/Empty";
import { ModalEvent2023FallItem } from "components/ModalPopup";
import {
ModalEvent2023FallItem,
ModalEvent2023FallRandomBox,
} from "components/ModalPopup";
import WhiteContainer from "components/WhiteContainer";

import theme from "tools/theme";
Expand All @@ -18,6 +21,7 @@ type EventItemComponentProps = {

const EventItemContainer = ({ value, fetchItems }: EventItemComponentProps) => {
const [isOpen, setIsOpen] = useState<boolean>(false);
const [rewardItem, setRewardItem] = useState<Nullable<EventItem>>(null);
const isSoldOut = value.stock <= 0;

return (
Expand Down Expand Up @@ -109,9 +113,17 @@ const EventItemContainer = ({ value, fetchItems }: EventItemComponentProps) => {
<ModalEvent2023FallItem
itemInfo={value}
fetchItems={fetchItems}
setRewardItem={setRewardItem}
isOpen={isOpen}
onChangeIsOpen={setIsOpen}
/>
{value.itemType === 3 && (
<ModalEvent2023FallRandomBox
isOpen={!!rewardItem}
onChangeIsOpen={() => setRewardItem(null)}
item={rewardItem || undefined}
/>
)}
</WhiteContainer>
);
};
Expand Down

0 comments on commit 3a59cf1

Please sign in to comment.