From 737cd0d7358079924fb246d36a37def6e76a3fc1 Mon Sep 17 00:00:00 2001 From: andyye <63383967+0ev@users.noreply.github.com> Date: Fri, 9 Feb 2024 22:17:06 +0900 Subject: [PATCH 1/2] Fix hooks --- packages/web/src/atoms/event2024SpringInfo.ts | 19 +++++++ .../web/src/components/Skeleton/index.tsx | 4 +- ...entEffect.ts => useEvent2023FallEffect.ts} | 2 +- .../hooks/event/useEvent2024SpringEffect.ts | 41 +++++++++++++++ .../event/useEvent2024SpringQuestComplete.ts | 42 +++++++++++++++ .../src/hooks/useFetchRecoilState/index.tsx | 20 +++++++- .../useFetchEvent2024SpringInfo.tsx | 31 +++++++++++ packages/web/src/types/event2024spring.d.ts | 51 +++++++++++++++++++ 8 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 packages/web/src/atoms/event2024SpringInfo.ts rename packages/web/src/hooks/event/{useEventEffect.ts => useEvent2023FallEffect.ts} (97%) create mode 100644 packages/web/src/hooks/event/useEvent2024SpringEffect.ts create mode 100644 packages/web/src/hooks/event/useEvent2024SpringQuestComplete.ts create mode 100644 packages/web/src/hooks/useFetchRecoilState/useFetchEvent2024SpringInfo.tsx create mode 100644 packages/web/src/types/event2024spring.d.ts diff --git a/packages/web/src/atoms/event2024SpringInfo.ts b/packages/web/src/atoms/event2024SpringInfo.ts new file mode 100644 index 000000000..d92f8cf06 --- /dev/null +++ b/packages/web/src/atoms/event2024SpringInfo.ts @@ -0,0 +1,19 @@ +import { Quest, QuestId } from "@/types/event2024spring"; + +import { atom } from "recoil"; + +export type Event2024SpringInfoType = Nullable<{ + isAgreeOnTermsOfEvent: boolean; + completedQuests: QuestId[]; + creditAmount: number; + ticket1Amount: number; + ticket2Amount: number; + quests: Quest[]; +}>; + +const event2024SpringInfoAtom = atom({ + key: "event2024SpringInfoAtom", + default: null, +}); + +export default event2024SpringInfoAtom; diff --git a/packages/web/src/components/Skeleton/index.tsx b/packages/web/src/components/Skeleton/index.tsx index 5cac93940..7b3ee4ba0 100644 --- a/packages/web/src/components/Skeleton/index.tsx +++ b/packages/web/src/components/Skeleton/index.tsx @@ -1,7 +1,7 @@ import { ReactNode, useMemo } from "react"; import { useLocation } from "react-router-dom"; -import { useEventEffect } from "@/hooks/event/useEventEffect"; +import { useEvent2023FallEffect } from "@/hooks/event/useEvent2023FallEffect"; import useCSSVariablesEffect from "@/hooks/skeleton/useCSSVariablesEffect"; import useChannelTalkEffect from "@/hooks/skeleton/useChannelTalkEffect"; import useFirebaseMessagingEffect from "@/hooks/skeleton/useFirebaseMessagingEffect"; @@ -65,7 +65,7 @@ const Skeleton = ({ children }: SkeletonProps) => { ); //#region event2023Fall - useEventEffect(); + useEvent2023FallEffect(); //#endregion useSyncRecoilStateEffect(); // loginIngo, taxiLocations, myRooms, notificationOptions 초기화 및 동기화 useI18nextEffect(); diff --git a/packages/web/src/hooks/event/useEventEffect.ts b/packages/web/src/hooks/event/useEvent2023FallEffect.ts similarity index 97% rename from packages/web/src/hooks/event/useEventEffect.ts rename to packages/web/src/hooks/event/useEvent2023FallEffect.ts index e4b0a3a8a..abae6e49a 100644 --- a/packages/web/src/hooks/event/useEventEffect.ts +++ b/packages/web/src/hooks/event/useEvent2023FallEffect.ts @@ -6,7 +6,7 @@ import { useValueRecoilState } from "@/hooks/useFetchRecoilState"; import toast from "@/tools/toast"; -export const useEventEffect = () => { +export const useEvent2023FallEffect = () => { const { completedQuests, quests } = useValueRecoilState("event2023FallInfo") || {}; diff --git a/packages/web/src/hooks/event/useEvent2024SpringEffect.ts b/packages/web/src/hooks/event/useEvent2024SpringEffect.ts new file mode 100644 index 000000000..45f88298e --- /dev/null +++ b/packages/web/src/hooks/event/useEvent2024SpringEffect.ts @@ -0,0 +1,41 @@ +import { useEffect, useRef } from "react"; + +import type { QuestId } from "@/types/event2024spring"; + +import { useValueRecoilState } from "@/hooks/useFetchRecoilState"; + +import toast from "@/tools/toast"; + +export const useEvent2024SpringEffect = () => { + const { completedQuests, quests } = + useValueRecoilState("event2024SpringInfo") || {}; + + const prevEventStatusRef = useRef(); + + useEffect(() => { + if (!completedQuests || !quests) return; + prevEventStatusRef.current = prevEventStatusRef.current || completedQuests; + if (prevEventStatusRef.current.length === completedQuests.length) return; + + const questsForCompare = [...completedQuests]; + prevEventStatusRef.current.forEach((questId) => { + const index = questsForCompare.indexOf(questId); + if (index < 0) return; + questsForCompare.splice(index, 1); + }); + questsForCompare.forEach((questId) => { + const quest = quests.find(({ id }) => id === questId); + if (!quest) return; + const notificationValue = { + type: "default" as const, + imageUrl: quest.imageUrl, + title: "퀘스트 완료", + subtitle: "새터반 택시대제전", + content: `축하합니다! "${quest.name}" 퀘스트를 달성하여 넙죽코인 ${quest.reward.credit}개를 획득하셨습니다.`, + button: { text: "확인하기", path: "/event/2024spring-missions" }, + }; + toast(notificationValue); + }); + prevEventStatusRef.current = completedQuests; + }, [completedQuests]); +}; diff --git a/packages/web/src/hooks/event/useEvent2024SpringQuestComplete.ts b/packages/web/src/hooks/event/useEvent2024SpringQuestComplete.ts new file mode 100644 index 000000000..659ba778b --- /dev/null +++ b/packages/web/src/hooks/event/useEvent2024SpringQuestComplete.ts @@ -0,0 +1,42 @@ +import { useCallback } from "react"; + +import type { QuestId } from "@/types/event2023fall"; + +import { + useFetchRecoilState, + useValueRecoilState, +} from "@/hooks/useFetchRecoilState"; +import { useAxios } from "@/hooks/useTaxiAPI"; + +export const useEvent2024SpringQuestComplete = () => { + const axios = useAxios(); + const fetchEvent2024SpringInfo = useFetchRecoilState("event2024SpringInfo"); + const { completedQuests, quests } = + useValueRecoilState("event2024SpringInfo") || {}; + + return useCallback( + (id: QuestId) => { + if (!completedQuests || !quests) return; + const questMaxCount = + quests?.find((quest) => quest.id === id)?.maxCount || 0; + const questCompletedCount = completedQuests?.filter( + (questId) => questId === id + ).length; + if (questCompletedCount >= questMaxCount) return; + if ( + [ + "roomSharing", + "eventSharingOnInstagram", + "purchaseSharingOnInstagram", + ].includes(id) + ) { + axios({ + url: `/events/2023fall/quests/complete/${id}`, + method: "post", + onSuccess: () => fetchEvent2024SpringInfo(), + }); + } else fetchEvent2024SpringInfo(); + }, + [completedQuests, fetchEvent2024SpringInfo, quests] + ); +}; diff --git a/packages/web/src/hooks/useFetchRecoilState/index.tsx b/packages/web/src/hooks/useFetchRecoilState/index.tsx index 33bae30d8..a6701ce67 100644 --- a/packages/web/src/hooks/useFetchRecoilState/index.tsx +++ b/packages/web/src/hooks/useFetchRecoilState/index.tsx @@ -5,6 +5,11 @@ import { useSetEvent2023FallInfo, useValueEvent2023FallInfo, } from "./useFetchEvent2023FallInfo"; +import { + useFetchEvent2024SpringInfo, + useSetEvent2024SpringInfo, + useValueEvent2024SpringInfo, +} from "./useFetchEvent2024SpringInfo"; import { useFetchLoginInfo, useSetLoginInfo, @@ -27,6 +32,7 @@ import { } from "./useFetchTaxiLocations"; import { Event2023FallInfoType } from "@/atoms/event2023FallInfo"; +import { Event2024SpringInfoType } from "@/atoms/event2024SpringInfo"; import { LoginInfoType } from "@/atoms/loginInfo"; import { MyRoomsType } from "@/atoms/myRooms"; import { notificationOptionsType } from "@/atoms/notificationOptions"; @@ -37,7 +43,8 @@ export type AtomName = | "taxiLocations" | "myRooms" | "notificationOptions" - | "event2023FallInfo"; + | "event2023FallInfo" + | "event2024SpringInfo"; type useValueRecoilStateType = { (atomName: "loginInfo"): LoginInfoType; @@ -45,6 +52,7 @@ type useValueRecoilStateType = { (atomName: "myRooms"): MyRoomsType; (atomName: "notificationOptions"): notificationOptionsType; (atomName: "event2023FallInfo"): Event2023FallInfoType; + (atomName: "event2024SpringInfo"): Event2024SpringInfoType; }; const _useValueRecoilState = (atomName: AtomName) => { switch (atomName) { @@ -58,6 +66,8 @@ const _useValueRecoilState = (atomName: AtomName) => { return useValueNotificationOptions(); case "event2023FallInfo": return useValueEvent2023FallInfo(); + case "event2024SpringInfo": + return useValueEvent2024SpringInfo(); } }; export const useValueRecoilState = @@ -75,6 +85,8 @@ export const useSetRecoilState = (atomName: AtomName) => { return useSetNotificationOptions(); case "event2023FallInfo": return useSetEvent2023FallInfo(); + case "event2024SpringInfo": + return useSetEvent2024SpringInfo(); } }; @@ -90,6 +102,8 @@ export const useFetchRecoilState = (atomName: AtomName) => { return useFetchNotificationOptions(); case "event2023FallInfo": return useFetchEvent2023FallInfo(); + case "event2024SpringInfo": + return useFetchEvent2024SpringInfo(); } }; @@ -116,6 +130,10 @@ export const useSyncRecoilStateEffect = () => { // event2023FallInfo 초기화 및 동기화 const fetchEvent2023FallInfo = useFetchRecoilState("event2023FallInfo"); useEffect(fetchEvent2023FallInfo, [userId]); + + // event2024SpringInfo 초기화 및 동기화 + const fetchEvent2024SpringInfo = useFetchRecoilState("event2024SpringInfo"); + useEffect(fetchEvent2024SpringInfo, [userId]); }; export const useIsLogin = (): boolean => { diff --git a/packages/web/src/hooks/useFetchRecoilState/useFetchEvent2024SpringInfo.tsx b/packages/web/src/hooks/useFetchRecoilState/useFetchEvent2024SpringInfo.tsx new file mode 100644 index 000000000..585e24dc3 --- /dev/null +++ b/packages/web/src/hooks/useFetchRecoilState/useFetchEvent2024SpringInfo.tsx @@ -0,0 +1,31 @@ +import { useCallback } from "react"; + +import { useAxios } from "@/hooks/useTaxiAPI"; +import { AxiosOption } from "@/hooks/useTaxiAPI/useAxios"; + +import event2024SpringInfoAtom from "@/atoms/event2024SpringInfo"; +import { useRecoilValue, useSetRecoilState } from "recoil"; + +import { eventMode } from "@/tools/loadenv"; + +export const useValueEvent2024SpringInfo = () => + useRecoilValue(event2024SpringInfoAtom); +export const useSetEvent2024SpringInfo = () => + useSetRecoilState(event2024SpringInfoAtom); +export const useFetchEvent2024SpringInfo = () => { + const setEvent2024SpringInfo = useSetEvent2024SpringInfo(); + const axios = useAxios(); + + return useCallback((onError?: AxiosOption["onError"]) => { + if (eventMode === "2024spring") { + axios({ + url: "/events/2024spring/global-state/", + method: "get", + onSuccess: (data) => setEvent2024SpringInfo(data), + onError: onError, + }); + } else { + setEvent2024SpringInfo(null); + } + }, []); +}; diff --git a/packages/web/src/types/event2024spring.d.ts b/packages/web/src/types/event2024spring.d.ts new file mode 100644 index 000000000..a678f38cb --- /dev/null +++ b/packages/web/src/types/event2024spring.d.ts @@ -0,0 +1,51 @@ +export type EventItem = { + _id: string; + name: string; + imageUrl: string; + instagramStoryStickerImageUrl?: string; + price: number; + description: string; + isDisabled: boolean; + stock: number; + itemType: number; +}; + +export type Transaction = { + _id: string; + amount: number; + comment: string; + createAt: Date; +} & ( + | { + type: "get"; + questId: string; + item: never; + } + | { + type: "use"; + item: EventItem; + questId: never; + } +); + +export type Quest = { + description: string; + id: QuestId; + imageUrl: string; + maxCount: number; + name: string; + reward: { credit: number }; +}; + +export type QuestId = + | "firstLogin" + | "payingAndSending" + | "firstRoomCreation" + | "roomSharing" + | "paying" + | "sending" + | "nicknameChanging" + | "accountChanging" + | "adPushAgreement" + | "eventSharing" + | "eventSharing5"; From 8db57a41eb986c083c358f8e488371265d97c823 Mon Sep 17 00:00:00 2001 From: andyye <63383967+0ev@users.noreply.github.com> Date: Fri, 9 Feb 2024 22:19:47 +0900 Subject: [PATCH 2/2] Fix: Skeleton --- packages/web/src/components/Skeleton/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/web/src/components/Skeleton/index.tsx b/packages/web/src/components/Skeleton/index.tsx index 7b3ee4ba0..40ff90508 100644 --- a/packages/web/src/components/Skeleton/index.tsx +++ b/packages/web/src/components/Skeleton/index.tsx @@ -1,7 +1,7 @@ import { ReactNode, useMemo } from "react"; import { useLocation } from "react-router-dom"; -import { useEvent2023FallEffect } from "@/hooks/event/useEvent2023FallEffect"; +import { useEvent2024SpringEffect } from "@/hooks/event/useEvent2024SpringEffect"; import useCSSVariablesEffect from "@/hooks/skeleton/useCSSVariablesEffect"; import useChannelTalkEffect from "@/hooks/skeleton/useChannelTalkEffect"; import useFirebaseMessagingEffect from "@/hooks/skeleton/useFirebaseMessagingEffect"; @@ -65,7 +65,7 @@ const Skeleton = ({ children }: SkeletonProps) => { ); //#region event2023Fall - useEvent2023FallEffect(); + useEvent2024SpringEffect(); //#endregion useSyncRecoilStateEffect(); // loginIngo, taxiLocations, myRooms, notificationOptions 초기화 및 동기화 useI18nextEffect();