Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Main branch update from Dev branch #822

Merged
merged 19 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading