Skip to content

Commit

Permalink
Merge pull request #822 from sparcs-kaist/dev
Browse files Browse the repository at this point in the history
Main branch update from Dev branch
  • Loading branch information
kmc7468 authored Sep 5, 2024
2 parents f7e789e + f1e198f commit b409cc2
Show file tree
Hide file tree
Showing 48 changed files with 3,304 additions and 93 deletions.
23 changes: 23 additions & 0 deletions packages/web/src/atoms/event2024FallInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Quest, QuestId } from "@/types/event2024fall";

import { atom } from "recoil";

type CompletedQuest = {
questId: QuestId;
completedAt: Date;
};

export type Event2024FallInfoType = Nullable<{
isAgreeOnTermsOfEvent: boolean;
isBanned: boolean;
creditAmount: number;
quests: Quest[];
completedQuests: CompletedQuest[];
}>;

const event2024FallInfoAtom = atom<Event2024FallInfoType>({
key: "event2024FallInfoAtom",
default: null,
});

export default event2024FallInfoAtom;
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import WhiteContainer from "@/components/WhiteContainer";
import theme from "@/tools/theme";

import { ReactComponent as CreditIcon } from "@/static/events/2023fallCredit.svg";
// ToDo : 2023fall 이미지
import { ReactComponent as Ticket1Icon } from "@/static/events/2023fallTicket1.svg";
// ToDo : 2023fall 이미지
import { ReactComponent as Ticket2Icon } from "@/static/events/2023fallTicket2.svg";
// ToDo : 2023fall 이미지

type CreditAmountStatusContainerProps = {
type?: "credit" | "ticket";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { useMemo, useState } from "react";
import { useState } from "react";

import { useIsLogin, useValueRecoilState } from "@/hooks/useFetchRecoilState";

import Button from "@/components/Button";
import LinkEvent2023FallInstagramStoryShare from "@/components/Link/LinkEvent2023FallInstagramStoryShare";
import {
ModalEvent2023FallJoin,
ModalEvent2024FallJoin,
ModalNotification,
} from "@/components/ModalPopup";
import WhiteContainer from "@/components/WhiteContainer";

import { deviceType } from "@/tools/loadenv";
import theme from "@/tools/theme";

const WhiteContainerSuggestJoinEvent = () => {
const isLogin = useIsLogin();
const { isAgreeOnTermsOfEvent, completedQuests } =
useValueRecoilState("event2023FallInfo") || {};
useValueRecoilState("event2024FallInfo") || {};
const isAdPushAgreementCompleted = completedQuests?.some(
({ questId }) => questId === "adPushAgreement"
);

const randomToken = useMemo(() => !!Math.floor(Math.random() * 2), []);
const [isOpenJoin, setIsOpenJoin] = useState<boolean>(false);
const [isOpenNotification, setIsOpenNotification] = useState<boolean>(false);

Expand Down Expand Up @@ -51,44 +51,7 @@ const WhiteContainerSuggestJoinEvent = () => {
이벤트 참여하기
</Button>
</WhiteContainer>
) : randomToken &&
completedQuests &&
!completedQuests.includes("adPushAgreement") ? (
<WhiteContainer>
<div css={styleText}>
<b>🌟 Taxi의 소울메이트</b>
</div>
<div css={styleText}>
Taxi 서비스를 잊지 않도록 가끔 찾아갈게요! 광고성 푸시 알림 수신
동의를 해주시면 방이 많이 모이는 시즌, 주변에 택시앱 사용자가 있을
때 알려드릴 수 있어요.
</div>
<Button
type="purple"
css={styleButton}
onClick={() => setIsOpenNotification(true)}
>
광고성 푸시 알림 수신 동의하고 송편 50개 얻기
</Button>
</WhiteContainer>
) : completedQuests &&
!completedQuests.includes("eventSharingOnInstagram") &&
deviceType.startsWith("app/") ? (
<WhiteContainer>
<div css={styleText}>
<b>🌟 나만 알기에는 아까운 이벤트</b>
</div>
<div css={styleText}>
추석에 맞춰 쏟아지는 혜택들. 나만 알 순 없죠. 인스타그램 친구들에게
스토리로 공유해보아요.
</div>
<LinkEvent2023FallInstagramStoryShare type="eventSharingOnInstagram">
<Button type="purple" css={styleButton}>
인스타그램 스토리에 공유하고 송편 100개 얻기
</Button>
</LinkEvent2023FallInstagramStoryShare>
</WhiteContainer>
) : completedQuests && !completedQuests.includes("adPushAgreement") ? (
) : completedQuests && !isAdPushAgreementCompleted ? (
<WhiteContainer>
<div css={styleText}>
<b>🌟 Taxi의 소울메이트</b>
Expand All @@ -107,7 +70,7 @@ const WhiteContainerSuggestJoinEvent = () => {
</Button>
</WhiteContainer>
) : null}
<ModalEvent2023FallJoin
<ModalEvent2024FallJoin
isOpen={isOpenJoin}
onChangeIsOpen={setIsOpenJoin}
/>
Expand Down
34 changes: 33 additions & 1 deletion packages/web/src/components/Footer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ import { ReactComponent as SparcsLogo } from "@/static/assets/sparcsLogos/Sparcs
import { ReactComponent as SparcsLogoWhite } from "@/static/events/2024SparcsLogoWithTextWhite.svg";

type FooterProps = {
type?: "only-logo" | "full" | "event-2023fall" | "event-2024spring";
type?:
| "only-logo"
| "full"
| "event-2023fall"
| "event-2024spring"
| "event-2024fall";
children?: ReactNode;
};

Expand Down Expand Up @@ -105,6 +110,33 @@ const Footer = ({ type = "full", children }: FooterProps) => {
</div>
</>
)}
{type === "event-2024fall" && (
<>
<ModalPrivacyPolicy
isOpen={isOpenPrivacyPolicy}
onChangeIsOpen={setIsOpenPrivacyPolicy}
/>
<ModalCredit
defaultSelectedCatagory="2024FallEvent"
isOpen={isOpenCredit}
onChangeIsOpen={setIsOpenCredit}
/>
<a className="popup-channeltalk">
<ButtonAboveFooter text="채널톡 문의하기" />
</a>
<ButtonAboveFooter
text="개인정보 처리방침"
onClick={onClickPrivacyPolicy}
/>
<Link to="/event/2023spring-guide" css={{ textDecoration: "none" }}>
<ButtonAboveFooter text="택시 살펴보기" />
</Link>
<ButtonAboveFooter
text="추석 이벤트를 만든 사람들"
onClick={onClickCredit}
/>
</>
)}
{type !== "event-2024spring" && (
<div css={{ padding: "6px" }}>
<a href="https://sparcs.org/" target="_blank" rel="noreferrer">
Expand Down
6 changes: 6 additions & 0 deletions packages/web/src/components/ModalPopup/ModalCredit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
members,
members2023FallEvent,
members2023SpringEvent,
members2024FallEvent,
members2024SpringEvent,
} from "@/static/members";

Expand Down Expand Up @@ -129,6 +130,11 @@ const ModalCredit = ({
name: t("page_credit.category_all"),
body: <BodyMembers values={members} />,
},
{
key: "2024FallEvent",
name: t("page_credit.category_2024fall_event"),
body: <BodyMembers values={members2024FallEvent} />,
},
{
key: "2024SpringEvent",
name: t("page_credit.category_2024spring_event"),
Expand Down
183 changes: 183 additions & 0 deletions packages/web/src/components/ModalPopup/ModalEvent2024FallItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import { Dispatch, SetStateAction, useCallback, useMemo, useRef } from "react";

import type { EventItem } from "@/types/event2024fall";

import { useDelayBoolean } from "@/hooks/useDelay";
import {
useFetchRecoilState,
useIsLogin,
useValueRecoilState,
} from "@/hooks/useFetchRecoilState";
import { useAxios } from "@/hooks/useTaxiAPI";

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

import alertAtom from "@/atoms/alert";
import { useSetRecoilState } from "recoil";

import { eventMode } from "@/tools/loadenv";
import theme from "@/tools/theme";

import { ReactComponent as CreditIcon } from "@/static/events/2023fallCredit.svg";
// ToDo : 2023fall 이미지
import AccountBalanceWalletRoundedIcon from "@mui/icons-material/AccountBalanceWalletRounded";

type ModalEvent2024FallItemProps = Parameters<typeof Modal>[0] & {
itemInfo: EventItem;
fetchItems?: () => void;
setRewardItem?: Dispatch<SetStateAction<Nullable<EventItem>>>;
setShareItem?: Dispatch<SetStateAction<Nullable<EventItem>>>;
};

const ModalEvent2024FallItem = ({
itemInfo,
fetchItems,
setRewardItem,
setShareItem,
...modalProps
}: ModalEvent2024FallItemProps) => {
const fetchEvent2024FallInfo = useFetchRecoilState("event2024FallInfo");
const event2024FallInfo = useValueRecoilState("event2024FallInfo");
const isLogin = useIsLogin();

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

const onClickOk = useCallback(async () => {
if (isRequesting.current) return;
isRequesting.current = true;
await axios({
url: `/events/2024fall/items/purchase/${itemInfo._id}`,
method: "post",
onSuccess: ({ reward }) => {
fetchEvent2024FallInfo();
fetchItems?.();
modalProps.onChangeIsOpen?.(false);
if (itemInfo.itemType === 3 && reward) {
setRewardItem?.(reward);
} else {
setShareItem?.(itemInfo);
}
},
onError: () => setAlert("구매를 실패하였습니다."),
});
isRequesting.current = false;
}, [
itemInfo._id,
fetchItems,
modalProps.onChangeIsOpen,
fetchEvent2024FallInfo,
]);

const [isDisabled, buttonText] = useMemo(
() =>
eventMode !== "2024fall"
? [true, "이벤트 기간이 아닙니다"]
: !event2024FallInfo || !isLogin
? [true, "로그인 후 구매가 가능합니다"]
: event2024FallInfo.creditAmount < itemInfo.price
? [true, "송편코인이 부족합니다"]
: [false, "구매하기"],
[eventMode, event2024FallInfo, itemInfo]
);

const styleTitle = {
...theme.font18,
display: "flex",
alignItems: "center",
margin: "0 8px 12px",
};
const styleIcon = {
fontSize: "21px",
margin: "0 4px 0 0",
};

return (
<Modal padding="16px 12px 12px" {...modalProps}>
<div css={styleTitle}>
<AccountBalanceWalletRoundedIcon style={styleIcon} />
구매하기
</div>
{itemInfo.itemType === 3 ? (
isDisplayRandomBox ? (
<BodyRandomBox isBoxOpend={false} />
) : (
<div css={{ textAlign: "center" }}>
<Loading />
</div>
)
) : (
<img
css={{
width: "100%",
borderRadius: "8px",
aspectRatio: "1/1",
}}
src={itemInfo.imageUrl}
alt={itemInfo.name}
/>
)}
<div
css={{
display: "flex",
flexDirection: "column",
alignItems: "left",
gap: "10px",
padding: "16px 4px",
}}
>
<div css={theme.font16_bold}>{itemInfo.name}</div>
<div css={theme.font14}>{itemInfo.description}</div>
<div
css={{
display: "flex",
gap: "4px",
}}
>
<CreditIcon css={{ width: "27px", height: "16px" }} />
<div>{itemInfo.price}</div>
</div>
</div>

<div
css={{
display: "flex",
justifyContent: "space-between",
}}
>
<Button
type="gray"
css={{
width: "calc(40% - 10px)",
padding: "10px 0 9px",
borderRadius: "8px",
...theme.font14,
}}
onClick={() => modalProps?.onChangeIsOpen?.(false)}
>
취소
</Button>
<Button
type="purple"
css={{
width: "60%",
padding: "10px 0 9px",
borderRadius: "8px",
...theme.font14_bold,
}}
onClick={onClickOk}
disabled={isDisabled}
>
{buttonText}
</Button>
</div>
</Modal>
);
};

export default ModalEvent2024FallItem;
Loading

0 comments on commit b409cc2

Please sign in to comment.