diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 795a1559..e7a80be2 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -2,7 +2,7 @@ "name": "@layer/mobile", "main": "expo-router/entry", "types": "./bridge/native.ts", - "version": "2.0.12", + "version": "2.0.13", "scripts": { "start": "expo start", "reset-project": "node ./scripts/reset-project.js", diff --git a/apps/mobile/provider/suspense-provider/index.tsx b/apps/mobile/provider/suspense-provider/index.tsx index f91d46e2..fb865270 100644 --- a/apps/mobile/provider/suspense-provider/index.tsx +++ b/apps/mobile/provider/suspense-provider/index.tsx @@ -16,7 +16,7 @@ import { router } from "expo-router"; import { createContext } from "@/lib/create-context"; const [Provider, useSuspense] = createContext<{ backgroundColor: string }>( - "SUSPENCE_PROVIDER" + "SUSPENCE_PROVIDER", ); const DEFAULT_MESSAGE = "데이터를 가져오고 있어요"; @@ -83,7 +83,7 @@ const SuspenseProvider = ({ children }: PropsWithChildren) => { const createAnimation = ( value: Animated.Value, toValue: number, - duration: number + duration: number, ): Animated.CompositeAnimation => { return Animated.timing(value, { toValue, diff --git a/apps/web/package.json b/apps/web/package.json index a8697976..459c50ee 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,7 +1,7 @@ { "name": "@layer/web", "private": true, - "version": "2.0.12", + "version": "2.0.13", "type": "module", "scripts": { "dev": "vite", diff --git a/apps/web/src/app/desktop/component/analysis/AnalysisDialog/AnalysisIndividualContents.tsx b/apps/web/src/app/desktop/component/analysis/AnalysisDialog/AnalysisIndividualContents.tsx index 164e5b72..9ff9335f 100644 --- a/apps/web/src/app/desktop/component/analysis/AnalysisDialog/AnalysisIndividualContents.tsx +++ b/apps/web/src/app/desktop/component/analysis/AnalysisDialog/AnalysisIndividualContents.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { Icon, IconType } from "@/component/common/Icon/Icon"; import { Typography } from "@/component/common/typography"; import { SATISTFACTION_COLOR } from "@/component/write/template/template.const"; @@ -187,7 +188,7 @@ export default function AnalysisIndividualContents({ individualAnalysis }: Analy display: flex; align-items: center; gap: 0.8rem; - z-index: 10; + z-index: ${Z_INDEX.localOverlay}; /* ---------- 말풍선 꼬리 ---------- */ &::after { diff --git a/apps/web/src/app/desktop/component/analysis/AnalysisDialog/AnalysisTeamContents.tsx b/apps/web/src/app/desktop/component/analysis/AnalysisDialog/AnalysisTeamContents.tsx index 4d6a8f59..b7f65e9f 100644 --- a/apps/web/src/app/desktop/component/analysis/AnalysisDialog/AnalysisTeamContents.tsx +++ b/apps/web/src/app/desktop/component/analysis/AnalysisDialog/AnalysisTeamContents.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { Icon } from "@/component/common/Icon/Icon"; import { Typography } from "@/component/common/typography"; @@ -202,7 +203,7 @@ export default function AnalysisTeamContents({ teamAnalyze }: AnalysisTeamConten display: flex; align-items: center; gap: 0.8rem; - z-index: 10; + z-index: ${Z_INDEX.localOverlay}; /* ---------- 말풍선 꼬리 ---------- */ &::after { diff --git a/apps/web/src/app/desktop/component/home/ActionItemsWrapper/index.tsx b/apps/web/src/app/desktop/component/home/ActionItemsWrapper/index.tsx index e7a6303d..a45b8b6b 100644 --- a/apps/web/src/app/desktop/component/home/ActionItemsWrapper/index.tsx +++ b/apps/web/src/app/desktop/component/home/ActionItemsWrapper/index.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { COOKIE_KEYS, LOCAL_STORAGE_KEYS } from "@/config/storage-keys"; import Cookies from "js-cookie"; @@ -199,7 +200,7 @@ export default function ActionItemsWrapper() { border: 1px solid ${DESIGN_TOKEN_COLOR.gray300}; top: 50%; transform: translateY(-50%); - z-index: 10; + z-index: ${Z_INDEX.localOverlay}; &::after { font-size: 1.4rem; diff --git a/apps/web/src/app/desktop/component/home/InProgressRetrospectsWrapper/index.tsx b/apps/web/src/app/desktop/component/home/InProgressRetrospectsWrapper/index.tsx index 54d4e567..1dbb5871 100644 --- a/apps/web/src/app/desktop/component/home/InProgressRetrospectsWrapper/index.tsx +++ b/apps/web/src/app/desktop/component/home/InProgressRetrospectsWrapper/index.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { Typography } from "@/component/common/typography"; @@ -51,7 +52,7 @@ export default function InProgressRetrospectsWrapper() { width: 8rem; height: 100%; background: linear-gradient(to left, ${DESIGN_TOKEN_COLOR.gray100}, rgba(255, 255, 255, 0)); - z-index: 2; + z-index: ${Z_INDEX.raised}; pointer-events: none; opacity: 1; transition: opacity 0.3s ease; @@ -66,7 +67,7 @@ export default function InProgressRetrospectsWrapper() { width: 8rem; height: 100%; background: linear-gradient(to right, ${DESIGN_TOKEN_COLOR.gray100}, rgba(255, 255, 255, 0)); - z-index: 2; + z-index: ${Z_INDEX.raised}; pointer-events: none; opacity: 0; transition: opacity 0.3s ease; @@ -101,7 +102,7 @@ export default function InProgressRetrospectsWrapper() { border: 1px solid ${DESIGN_TOKEN_COLOR.gray200}; top: 65%; transform: translateY(-50%); - z-index: 10; + z-index: ${Z_INDEX.localOverlay}; &::after { font-size: 1.6rem; diff --git a/apps/web/src/app/desktop/component/retrospect/template/list/TemplateListDetailItem/index.tsx b/apps/web/src/app/desktop/component/retrospect/template/list/TemplateListDetailItem/index.tsx index 4860b8b8..637c7c7c 100644 --- a/apps/web/src/app/desktop/component/retrospect/template/list/TemplateListDetailItem/index.tsx +++ b/apps/web/src/app/desktop/component/retrospect/template/list/TemplateListDetailItem/index.tsx @@ -14,7 +14,12 @@ import { retrospectInitialState } from "@/store/retrospect/retrospectInitial"; import { TemplateListConform } from "../TemplateListConform"; import { useSearchParams } from "react-router-dom"; -function TemplateListDetailItem({ templateId }: { templateId: number }) { +interface TemplateListDetailItemProps { + templateId: number; + readOnly?: boolean; +} + +function TemplateListDetailItem({ templateId, readOnly = false }: TemplateListDetailItemProps) { const { tabs, curTab, selectTab } = useTabs(["기본", "질문구성"] as const); const { data } = useGetTemplateInfo({ templateId: templateId }); const { heading, description } = splitTemplateIntroduction(data.introduction); @@ -23,6 +28,7 @@ function TemplateListDetailItem({ templateId }: { templateId: number }) { const [searchParams, setSearchParams] = useSearchParams(); const type = searchParams.get("template_type"); const templateMode = searchParams.get("template_mode"); + const isReadOnlyMode = templateMode === "readonly" || readOnly; /** * @description 회고 템플릿 선택하기 버튼 클릭 핸들러 @@ -65,7 +71,7 @@ function TemplateListDetailItem({ templateId }: { templateId: number }) { {/* 읽기 전용(readOnly = true)일 경우에는 버튼 컨테이너를 노출시키지 않아요 */} - {templateMode !== "readonly" && ( + {!isReadOnlyMode && ( 선택하기 diff --git a/apps/web/src/app/desktop/component/retrospect/template/list/TemplateListItem/index.tsx b/apps/web/src/app/desktop/component/retrospect/template/list/TemplateListItem/index.tsx index a0b640a5..0fa211f1 100644 --- a/apps/web/src/app/desktop/component/retrospect/template/list/TemplateListItem/index.tsx +++ b/apps/web/src/app/desktop/component/retrospect/template/list/TemplateListItem/index.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { Typography } from "@/component/common/typography"; import { Tag } from "@/component/common/tag"; @@ -36,7 +37,7 @@ export function TemplateListItem({ id, title, tag, imageUrl }: DesktopTemplateLi step: "listTemplateDetail", contents: , templateTag: tag, - overlayIndex: 10002, + overlayIndex: Z_INDEX.popoverRaised, }); }; diff --git a/apps/web/src/app/desktop/component/retrospect/template/list/TemplateListTab/index.tsx b/apps/web/src/app/desktop/component/retrospect/template/list/TemplateListTab/index.tsx index 988433fc..a77f2a60 100644 --- a/apps/web/src/app/desktop/component/retrospect/template/list/TemplateListTab/index.tsx +++ b/apps/web/src/app/desktop/component/retrospect/template/list/TemplateListTab/index.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useTabs } from "@/hooks/useTabs"; @@ -31,7 +32,7 @@ export function TemplateListTab({ tabs, curTab, selectTab, Tab display: inline-flex; gap: 0.8rem; padding-top: 2rem; - z-index: 1001; + z-index: ${Z_INDEX.sticky}; border-bottom: 0.2rem solid ${DESIGN_TOKEN_COLOR.gray200}; `, ]} diff --git a/apps/web/src/app/desktop/component/retrospect/template/list/index.tsx b/apps/web/src/app/desktop/component/retrospect/template/list/index.tsx index 1fb320de..1637fa86 100644 --- a/apps/web/src/app/desktop/component/retrospect/template/list/index.tsx +++ b/apps/web/src/app/desktop/component/retrospect/template/list/index.tsx @@ -2,7 +2,11 @@ import { useRequiredParams } from "@/hooks/useRequiredParams"; import { useTabs } from "@/hooks/useTabs"; import { useToast } from "@/hooks/useToast"; import { css } from "@emotion/react"; -import { createContext, useEffect, useRef } from "react"; +import { createContext, useEffect } from "react"; +import { useAtomValue } from "jotai"; +import { currentSpaceState } from "@/store/space/spaceAtom"; +import { branchLayoutAtom } from "@/store/auth/authAtom"; +import { isSpaceLeader } from "@/utils/userUtil"; import { TemplateListTabButton } from "./TemplateListTab/TemplateListTabButton"; import { CustomTemplateList } from "@/component/retrospect/template/list"; import { useGetDefaultTemplateList } from "@/hooks/api/template/useGetDefaultTemplateList"; @@ -16,8 +20,6 @@ import { DESIGN_TOKEN_COLOR } from "@/style/designTokens"; import { useSearchParams } from "react-router-dom"; import { trackEvent } from "@/lib/google-analytics"; import { GA_EVENTS } from "@/lib/google-analytics/events"; -import { useAtomValue } from "jotai"; -import { branchLayoutAtom } from "@/store/auth/authAtom"; import { Button } from "@/component/common/button"; import { useFunnelModal } from "@/hooks/useFunnelModal"; import { TemplateRecommend } from "../recommend"; @@ -112,7 +114,8 @@ function RecommendBanner({ onClickRecommend }: { onClickRecommend: () => void }) export function TemplateList() { const { toast } = useToast(); - const isLeader = useRef(false); + const currentSpace = useAtomValue(currentSpaceState); + const isLeader = isSpaceLeader(currentSpace?.leader?.id); const params = useRequiredParams<{ spaceId?: string }>(); const [searchParams] = useSearchParams(); const spaceId = params.spaceId || searchParams.get("spaceId") || ""; @@ -163,7 +166,7 @@ export function TemplateList() { margin-top: 2rem; `} > - + {branchLayout === "A" ? : }
    { // 사용자가 템플릿을 변경하거나, 회고를 생성할 때 변경된 정보가 있으면 스페이스 정보를 다시 가져옵니다. await queryClient.invalidateQueries({ - queryKey: ["getSpaceInfo", spaceIdNumber], + queryKey: spaceQueryKeys.info(spaceIdNumber), }); // 사용자가 회고를 추가했다면, 회고 리스트 조회를 다시 리패치합니다. await queryClient.invalidateQueries({ - queryKey: ["getRetrospects", spaceIdNumber], + queryKey: retrospectQueryKeys.list(spaceIdNumber), }); navigate(PATHS.spaceDetail(String(spaceIdNumber))); closeFunnelModal(); diff --git a/apps/web/src/app/desktop/component/retrospectWrite/complete/index.tsx b/apps/web/src/app/desktop/component/retrospectWrite/complete/index.tsx index 838dadd7..94da4102 100644 --- a/apps/web/src/app/desktop/component/retrospectWrite/complete/index.tsx +++ b/apps/web/src/app/desktop/component/retrospectWrite/complete/index.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css, keyframes } from "@emotion/react"; import Lottie from "lottie-react"; import { useEffect, useState } from "react"; @@ -112,20 +113,20 @@ export function RetrospectWriteComplete() { div:nth-of-type(1) { background-color: #243753; - z-index: 3; + z-index: ${Z_INDEX.elevated}; position: relative; } div:nth-of-type(2) { background-color: #c4d7fd; - z-index: 2; + z-index: ${Z_INDEX.raised}; transform: rotate(-8deg); animation: ${CARD_ANIMATION.FIRST_CARD} 0.6s ease-in-out; } div:nth-of-type(3) { background-color: #a7c4fc; - z-index: 1; + z-index: ${Z_INDEX.base}; transform: rotate(-16deg); animation: ${CARD_ANIMATION.SECOND_CARD} 0.8s ease-in-out; } @@ -144,7 +145,7 @@ export function RetrospectWriteComplete() { right: -5%; width: 20%; height: auto; - z-index: 4; + z-index: ${Z_INDEX.foreground}; `} />
    )} diff --git a/apps/web/src/app/desktop/component/retrospectWrite/prepare/index.tsx b/apps/web/src/app/desktop/component/retrospectWrite/prepare/index.tsx index 275111e3..c4422cb2 100644 --- a/apps/web/src/app/desktop/component/retrospectWrite/prepare/index.tsx +++ b/apps/web/src/app/desktop/component/retrospectWrite/prepare/index.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { useMixpanel } from "@/lib/provider/mix-pannel-provider"; import { Header } from "@/component/common/header"; import { css } from "@emotion/react"; @@ -58,7 +59,7 @@ export function Prepare({ spaceId, retrospectId, title, introduction }: PrepareP width: 100%; height: 40%; top: -10%; - z-index: 10000; + z-index: ${Z_INDEX.overlay}; transform: scale(1, -1); `} /> @@ -70,7 +71,7 @@ export function Prepare({ spaceId, retrospectId, title, introduction }: PrepareP width: 100%; height: 60%; bottom: 0; - z-index: 10000; + z-index: ${Z_INDEX.overlay}; `} /> , - overlayIndex: 10002, + overlayIndex: Z_INDEX.popoverRaised, }); } else if (recommendTemplateType === "recommendation") { nextPhase(); @@ -704,9 +706,25 @@ function SelectRetrospectTemplateFunnel() { // 3단계 퍼널: 회고 템플릿 확정 function ConfirmRetrospectTemplateFunnel() { - const { selectedRecommendTemplateId, setFlow, goBackToTemplateSelect, setDetailFrom } = useContext(PhaseContext); + const { selectedRecommendTemplateId, setFlow, goBackToTemplateSelect } = useContext(PhaseContext); if (!selectedRecommendTemplateId) return; const { data: templateData } = useGetSimpleTemplateInfo(selectedRecommendTemplateId); + const { openFunnelModal, closeFunnelModal } = useFunnelModal(); + + const handleShowTemplateDetailInfo = () => { + openFunnelModal({ + title: templateData.title, + step: "listTemplateDetail", + contents: , + templateTag: templateData.templateName, + overlayIndex: 100002, + onPrevious: closeFunnelModal, + options: { + quitButton: false, + }, + }); + }; + return (
    @@ -730,8 +748,7 @@ function ConfirmRetrospectTemplateFunnel() { cursor: pointer; `} onClick={() => { - setDetailFrom("confirm"); - setFlow("INFO", 3); + handleShowTemplateDetailInfo(); }} >
    , templateTag: templateName, - overlayIndex: 100002, + overlayIndex: Z_INDEX.modalRaised, onPrevious: closeFunnelModal, }); }; @@ -1199,6 +1216,7 @@ function CreateRetrospectQuestionFunnel() { function CreateRetrospectDeadlineFunnel() { const { questions, selectedRecommendTemplate, setSpaceId, deadLine, setDeadLine, title, description, selectedCategory, setFlow } = useContext(PhaseContext); + const { isNewForm, hasChangedOriginal } = useAtomValue(retrospectCreateAtom); const { selectedValue, isChecked, onChange } = useRadioButton(); const { toast } = useToast(); const { mutateAsync: postSpace } = useApiPostSpace(); @@ -1231,8 +1249,8 @@ function CreateRetrospectDeadlineFunnel() { introduction: "", questions: [...DEFAULT_QUESTIONS, ...questions], deadline: deadLine, - isNewForm: false, - hasChangedOriginal: false, + isNewForm, + hasChangedOriginal, curFormId: selectedRecommendTemplate!.id, } as RetrospectCreateReq; const res = await postRetrospect( @@ -1242,7 +1260,7 @@ function CreateRetrospectDeadlineFunnel() { toast.success("스페이스와 회고가 생성되었어요!"); // 스페이스 생성이 완료되면 스페이스 목록을 리패치 queryClient.invalidateQueries({ - queryKey: ["spaces"], + queryKey: spaceQueryKeys.lists, }); setFlow("COMPLETE", 0); }, diff --git a/apps/web/src/app/mobile/write/RetrospectWriteCompletePage.tsx b/apps/web/src/app/mobile/write/RetrospectWriteCompletePage.tsx index 1353fb4e..eda12618 100644 --- a/apps/web/src/app/mobile/write/RetrospectWriteCompletePage.tsx +++ b/apps/web/src/app/mobile/write/RetrospectWriteCompletePage.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css, keyframes } from "@emotion/react"; import Lottie from "lottie-react"; import { Fragment, useEffect, useState } from "react"; @@ -104,20 +105,20 @@ export function RetrospectWriteCompletePage() { div:nth-of-type(1) { background-color: #243753; - z-index: 3; + z-index: ${Z_INDEX.elevated}; position: relative; } div:nth-of-type(2) { background-color: #c4d7fd; - z-index: 2; + z-index: ${Z_INDEX.raised}; transform: rotate(-8deg); animation: ${CARD_ANIMATION.FIRST_CARD} 0.6s ease-in-out; } div:nth-of-type(3) { background-color: #a7c4fc; - z-index: 1; + z-index: ${Z_INDEX.base}; transform: rotate(-16deg); animation: ${CARD_ANIMATION.SECOND_CARD} 0.8s ease-in-out; } @@ -136,7 +137,7 @@ export function RetrospectWriteCompletePage() { right: -5%; width: 20%; height: auto; - z-index: 4; + z-index: ${Z_INDEX.foreground}; `} />
    )} diff --git a/apps/web/src/component/BottomSheet/BottomSheet.tsx b/apps/web/src/component/BottomSheet/BottomSheet.tsx index 78bd667e..a94a6b49 100644 --- a/apps/web/src/component/BottomSheet/BottomSheet.tsx +++ b/apps/web/src/component/BottomSheet/BottomSheet.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css, Interpolation, Theme } from "@emotion/react"; import { ReactElement, useEffect, useState } from "react"; @@ -39,7 +40,7 @@ export function BottomSheet({ id, title, contents, handler = false, quitButton = transform: translate3d(-50%, -50%, 0); background-color: ${isVisible ? `rgba(24, 24, 24, 60%)` : `transparent`}; transition: 0.4s all; - z-index: 10001; + z-index: ${Z_INDEX.popover}; ${!isVisible && css` @@ -64,7 +65,7 @@ export function BottomSheet({ id, title, contents, handler = false, quitButton = border-top-right-radius: 1.6rem; box-shadow: 0 4rem 4rem rgba(0, 0, 0, 0.25); transition: transform 200ms ease-out; - z-index: 100000000; + z-index: ${Z_INDEX.bottomSheet}; padding: 2rem; box-sizing: border-box; background-color: #fff; diff --git a/apps/web/src/component/BottomSheet/component/BottomSheetContent.tsx b/apps/web/src/component/BottomSheet/component/BottomSheetContent.tsx index ca9c7538..9d6d4567 100644 --- a/apps/web/src/component/BottomSheet/component/BottomSheetContent.tsx +++ b/apps/web/src/component/BottomSheet/component/BottomSheetContent.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { forwardRef, PropsWithChildren } from "react"; @@ -7,7 +8,7 @@ export const BottomSheetContent = forwardRef( ref={ref} css={css` -webkit-overflow-scrolling: touch; - z-index: 999; + z-index: ${Z_INDEX.sheetContent}; background-color: inherit; position: relative; height: 100%; diff --git a/apps/web/src/component/BottomSheet/component/BottomSheetHeader.tsx b/apps/web/src/component/BottomSheet/component/BottomSheetHeader.tsx index d8bef16a..a8d1ddd5 100644 --- a/apps/web/src/component/BottomSheet/component/BottomSheetHeader.tsx +++ b/apps/web/src/component/BottomSheet/component/BottomSheetHeader.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { BottomSheetType } from "@/component/BottomSheet/BottomSheet.tsx"; @@ -48,7 +49,7 @@ export function BottomSheetHeader({ title, handler, quitButton }: Pick diff --git a/apps/web/src/component/common/Confetti/Confetti.tsx b/apps/web/src/component/common/Confetti/Confetti.tsx index e047a59c..548a1e06 100644 --- a/apps/web/src/component/common/Confetti/Confetti.tsx +++ b/apps/web/src/component/common/Confetti/Confetti.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { Fragment, useCallback, useEffect, useRef } from "react"; import ReactCanvasConfetti from "react-canvas-confetti"; import { type IProps } from "react-canvas-confetti"; @@ -10,7 +11,7 @@ const canvasStyles = { top: "50%", left: "50%", transform: "translate(-50%, -50%)", - zIndex: 9999, + zIndex: Z_INDEX.notification, } as React.CSSProperties; type ConfettiProps = { diff --git a/apps/web/src/component/common/LocalNavigationBar/UserProfileDropdown.tsx b/apps/web/src/component/common/LocalNavigationBar/UserProfileDropdown.tsx index 31090585..58d39160 100644 --- a/apps/web/src/component/common/LocalNavigationBar/UserProfileDropdown.tsx +++ b/apps/web/src/component/common/LocalNavigationBar/UserProfileDropdown.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { forwardRef } from "react"; @@ -28,7 +29,7 @@ export const UserProfileDropdown = forwardRef diff --git a/apps/web/src/component/common/Modal/DesktopFunnelModal.tsx b/apps/web/src/component/common/Modal/DesktopFunnelModal.tsx index 2391210d..a3660802 100644 --- a/apps/web/src/component/common/Modal/DesktopFunnelModal.tsx +++ b/apps/web/src/component/common/Modal/DesktopFunnelModal.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { Portal } from "@/component/common/Portal"; import { ANIMATION } from "@/style/common/animation"; @@ -144,6 +145,9 @@ type DesktopModalHeaderProps = { }; function DesktopFunnelModalHeader({ title, tag, backgroundColor, isRetrospectWrite, onBack, onClose }: DesktopModalHeaderProps) { + const { funnelModalState } = useFunnelModal(); + const { previousButton, quitButton } = funnelModalState.options!; + return (
    - {onBack && ( + {onBack && previousButton && (
    - - + > + + + )}
    ); } diff --git a/apps/web/src/component/common/Modal/DesktopModal/DesktopModal.tsx b/apps/web/src/component/common/Modal/DesktopModal/DesktopModal.tsx index 06e036cc..13e3a0d2 100644 --- a/apps/web/src/component/common/Modal/DesktopModal/DesktopModal.tsx +++ b/apps/web/src/component/common/Modal/DesktopModal/DesktopModal.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { Portal } from "@/component/common/Portal"; @@ -49,7 +50,7 @@ export default function DesktopModal() { display: flex; justify-content: center; align-items: center; - z-index: 10001; + z-index: ${Z_INDEX.popover}; background-color: rgba(0, 0, 0, 0.5); `} > diff --git a/apps/web/src/component/common/Modal/FullModal.tsx b/apps/web/src/component/common/Modal/FullModal.tsx index 62658498..a6bc1334 100644 --- a/apps/web/src/component/common/Modal/FullModal.tsx +++ b/apps/web/src/component/common/Modal/FullModal.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { Portal } from "@/component/common/Portal"; @@ -21,7 +22,7 @@ export function FullModal({ children }: FullModalProps) { display: flex; justify-content: center; align-items: center; - z-index: 10000; + z-index: ${Z_INDEX.overlay}; `} >
    diff --git a/apps/web/src/component/common/Modal/Member/InviteMemberModal.tsx b/apps/web/src/component/common/Modal/Member/InviteMemberModal.tsx index ebf52f7c..0b7bde8a 100644 --- a/apps/web/src/component/common/Modal/Member/InviteMemberModal.tsx +++ b/apps/web/src/component/common/Modal/Member/InviteMemberModal.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { IconButton } from "@/component/common/button"; @@ -92,7 +93,7 @@ export function InviteMemberModal({ isOpen, onClose, spaceId }: InviteMemberModa display: flex; justify-content: center; align-items: center; - z-index: 99999; + z-index: ${Z_INDEX.modal}; `} onClick={handleBackgroundClick} > diff --git a/apps/web/src/component/common/Modal/MidModal.tsx b/apps/web/src/component/common/Modal/MidModal.tsx index fa77e9f0..f5f0620a 100644 --- a/apps/web/src/component/common/Modal/MidModal.tsx +++ b/apps/web/src/component/common/Modal/MidModal.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useRef } from "react"; @@ -41,7 +42,7 @@ export function MidModal({ title, content, leftText = "취소", rightText = "삭 justify-content: center; text-align: center; box-sizing: border-box; - z-index: 99999; + z-index: ${Z_INDEX.modal}; `} ref={containerRef} onClick={handleBackgroundClick} diff --git a/apps/web/src/component/common/Modal/Modal.tsx b/apps/web/src/component/common/Modal/Modal.tsx index e00bd2eb..8e6eb5a7 100644 --- a/apps/web/src/component/common/Modal/Modal.tsx +++ b/apps/web/src/component/common/Modal/Modal.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useRef } from "react"; @@ -30,7 +31,7 @@ export function Modal() { display: flex; justify-content: center; align-items: center; - z-index: 999999; + z-index: ${Z_INDEX.dimmed}; `} ref={containerRef} onClick={(e) => { diff --git a/apps/web/src/component/common/Modal/UserSetting/AccountSettingsModal.tsx b/apps/web/src/component/common/Modal/UserSetting/AccountSettingsModal.tsx index 271a5a09..e46bc629 100644 --- a/apps/web/src/component/common/Modal/UserSetting/AccountSettingsModal.tsx +++ b/apps/web/src/component/common/Modal/UserSetting/AccountSettingsModal.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useState, useRef } from "react"; import axios from "axios"; @@ -14,26 +15,29 @@ import { DESIGN_TOKEN_COLOR } from "@/style/designTokens"; import { ANIMATION } from "@/style/common/animation"; import { Input, InputLabelContainer, Label } from "@/component/common/input"; import { useInput } from "@/hooks/useInput"; -import { DeleteAccountConfirmModal } from "./DeleteAccountConfirmModal"; import { api } from "@/api"; import { usePatchUpdateProfile } from "@/hooks/api/user/usePatchUpdateProfile"; import { useDeleteUser } from "@/hooks/api/user/useDeleteUser"; import { useAtom } from "jotai"; import { authAtom } from "@/store/auth/authAtom"; +import { useModal } from "@/hooks/useModal"; type AccountSettingsModalProps = { isOpen: boolean; onClose: () => void; }; +type AccountSettingModalType = "settings" | "deleteAccount"; + export function AccountSettingsModal({ isOpen, onClose }: AccountSettingsModalProps) { if (!isOpen) return null; - const [modalView, setModalView] = useState<"settings" | "deleteAccount">("settings"); + const [modalView, setModalView] = useState("settings"); const [{ name, imageUrl }] = useAtom(authAtom); - const [showConfirmModal, setShowConfirmModal] = useState(false); + const { open, close, setProgress } = useModal(); + const nameInput = useInput(name); const [selectedImage, setSelectedImage] = useState(imageUrl); const fileInputRef = useRef(null); @@ -99,14 +103,31 @@ export function AccountSettingsModal({ isOpen, onClose }: AccountSettingsModalPr if (memberId) { // deleteReasons를 boolean 배열로 변환 const booleans = [deleteReasons.notUseful, deleteReasons.uncomfortable, deleteReasons.other]; - - deleteUser({ - memberId: Number(memberId), - booleans: booleans, - description: feedbackInput.value, + open({ + title: "계정탈퇴", + contents: "계정 탈퇴시 모든 회고 정보가 날아가요.\n정말 계정 탈퇴를 진행하시겠어요?", + onConfirm: () => { + setProgress(true); + deleteUser( + { + memberId: Number(memberId), + booleans: booleans, + description: feedbackInput.value, + }, + { + onSuccess: () => { + close(); + onClose(); + }, + onSettled: () => setProgress(false), + }, + ); + }, + onClose: () => close(), + options: { + autoClose: false, + }, }); - setShowConfirmModal(false); - onClose(); } }; @@ -125,7 +146,7 @@ export function AccountSettingsModal({ isOpen, onClose }: AccountSettingsModalPr display: flex; justify-content: center; align-items: center; - z-index: 99999; + z-index: ${Z_INDEX.modal}; `} onClick={handleBackgroundClick} > @@ -419,14 +440,17 @@ export function AccountSettingsModal({ isOpen, onClose }: AccountSettingsModalPr onClick={() => { if (modalView === "deleteAccount") { if (hasSelectedReason) { - setShowConfirmModal(true); + handleDeleteAccount(); } } else { handleSubmit(); } }} > - + {modalView === "deleteAccount" ? "계정 탈퇴" : "완료"} @@ -434,9 +458,6 @@ export function AccountSettingsModal({ isOpen, onClose }: AccountSettingsModalPr
    - - {/* 계정 탈퇴 확인 모달 */} - setShowConfirmModal(false)} onConfirm={handleDeleteAccount} /> ); } diff --git a/apps/web/src/component/common/Modal/UserSetting/DeleteAccountConfirmModal.tsx b/apps/web/src/component/common/Modal/UserSetting/DeleteAccountConfirmModal.tsx deleted file mode 100644 index c3cbdb02..00000000 --- a/apps/web/src/component/common/Modal/UserSetting/DeleteAccountConfirmModal.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { MidModal } from "../MidModal"; - -type DeleteAccountConfirmModalProps = { - isOpen: boolean; - onClose: () => void; - onConfirm: () => void; -}; - -export function DeleteAccountConfirmModal({ isOpen, onClose, onConfirm }: DeleteAccountConfirmModalProps) { - if (!isOpen) return null; - - return ( - - ); -} diff --git a/apps/web/src/component/common/Modal/UserSetting/FeedbackModal.tsx b/apps/web/src/component/common/Modal/UserSetting/FeedbackModal.tsx index 7bc67bf5..6e105bd8 100644 --- a/apps/web/src/component/common/Modal/UserSetting/FeedbackModal.tsx +++ b/apps/web/src/component/common/Modal/UserSetting/FeedbackModal.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useState } from "react"; @@ -55,7 +56,7 @@ export function FeedbackModal({ isOpen, onClose }: FeedbackModalProps) { display: flex; justify-content: center; align-items: center; - z-index: 99999; + z-index: ${Z_INDEX.modal}; `} onClick={handleBackgroundClick} > diff --git a/apps/web/src/component/common/Modal/UserSetting/HelpModal.tsx b/apps/web/src/component/common/Modal/UserSetting/HelpModal.tsx index 0d0b6cda..a66e7475 100644 --- a/apps/web/src/component/common/Modal/UserSetting/HelpModal.tsx +++ b/apps/web/src/component/common/Modal/UserSetting/HelpModal.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useState } from "react"; @@ -331,7 +332,7 @@ export function HelpModal({ isOpen, onClose }: HelpModalProps) { display: flex; justify-content: center; align-items: center; - z-index: 99999; + z-index: ${Z_INDEX.modal}; `} onClick={handleBackgroundClick} > diff --git a/apps/web/src/component/common/Toast/Toast.tsx b/apps/web/src/component/common/Toast/Toast.tsx index 3e5c17c4..589a375b 100644 --- a/apps/web/src/component/common/Toast/Toast.tsx +++ b/apps/web/src/component/common/Toast/Toast.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { Portal } from "@/component/common/Portal"; @@ -19,7 +20,7 @@ export function Toast() { top: 10px; left: 50%; transform: translate(-50%, 0); - z-index: 1000000; + z-index: ${Z_INDEX.toast}; `} > {toastDataState.map((toast) => ( diff --git a/apps/web/src/component/common/Tooltip/index.tsx b/apps/web/src/component/common/Tooltip/index.tsx index 205259a6..ac6b9526 100644 --- a/apps/web/src/component/common/Tooltip/index.tsx +++ b/apps/web/src/component/common/Tooltip/index.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { DESIGN_TOKEN_COLOR } from "@/style/designTokens"; import { createContext, @@ -242,7 +243,7 @@ const TooltipContent = ({ children, className = "", sideOffset = 16, tag, arrow const trigger = triggerRef.current; const style: CSSProperties = { position: "absolute", - zIndex: 9999, + zIndex: Z_INDEX.notification, backgroundColor: theme === "blue" ? DESIGN_TOKEN_COLOR.blue600 : DESIGN_TOKEN_COLOR.gray900, color: "#FFFFFF", padding: "1rem 1.4rem", diff --git a/apps/web/src/component/common/appBar/AppBar.tsx b/apps/web/src/component/common/appBar/AppBar.tsx index ecc66ede..87a96a4a 100644 --- a/apps/web/src/component/common/appBar/AppBar.tsx +++ b/apps/web/src/component/common/appBar/AppBar.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css, Interpolation, Theme } from "@emotion/react"; import { useAtom } from "jotai"; import { forwardRef, useEffect } from "react"; @@ -59,7 +60,7 @@ export const AppBar = forwardRef(function ( left: 50%; transform: translateX(-50%); box-sizing: border-box; - z-index: 99; + z-index: ${Z_INDEX.appBar}; `, style, ]} diff --git a/apps/web/src/component/common/button/ButtonProvider.tsx b/apps/web/src/component/common/button/ButtonProvider.tsx index 9c030277..b0e84e0c 100644 --- a/apps/web/src/component/common/button/ButtonProvider.tsx +++ b/apps/web/src/component/common/button/ButtonProvider.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css, Interpolation, Theme } from "@emotion/react"; import { Children, cloneElement, isValidElement, PropsWithChildren } from "react"; @@ -58,7 +59,7 @@ export const ButtonProvider = ({ padding: ${isDesktop ? "0.8rem 0 1.6rem" : "4rem 0 2rem"}; background-color: ${isDesktop && funnelModalState.step === "listTemplateDetail" ? "#fff" : "transparent"}; margin-top: auto; - z-index: 10000; + z-index: ${Z_INDEX.overlay}; `, onlyContainerStyle, ]} @@ -72,7 +73,7 @@ export const ButtonProvider = ({ right: 0; bottom: 0; margin: ${isDesktop ? "" : "0 -2rem"}; - z-index: -1; + z-index: ${Z_INDEX.behind}; background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, var(--parent-bg-color) 57.38%); `} /> diff --git a/apps/web/src/component/common/dropdownMenu/DropdownMenu.tsx b/apps/web/src/component/common/dropdownMenu/DropdownMenu.tsx index c693295a..be97799f 100644 --- a/apps/web/src/component/common/dropdownMenu/DropdownMenu.tsx +++ b/apps/web/src/component/common/dropdownMenu/DropdownMenu.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { Placement } from "@popperjs/core"; import { OffsetModifier } from "@popperjs/core/lib/modifiers/offset"; @@ -102,7 +103,7 @@ function Content({ children }: { children: React.ReactNode }) { flex-direction: column; position: absolute; bottom: 0; - z-index: 10001; + z-index: ${Z_INDEX.popover}; background-color: ${DESIGN_TOKEN_COLOR.gray00}; border-radius: 0.8rem; box-shadow: ${DESIGN_TOKEN_COLOR.shadow.shadow300}; diff --git a/apps/web/src/component/common/tabs/Tabs.tsx b/apps/web/src/component/common/tabs/Tabs.tsx index 58efa75f..e3e04e77 100644 --- a/apps/web/src/component/common/tabs/Tabs.tsx +++ b/apps/web/src/component/common/tabs/Tabs.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css, Interpolation, Theme } from "@emotion/react"; import { useTabs } from "@/hooks/useTabs"; @@ -20,7 +21,7 @@ export function Tabs({ tabs, curTab, selectTab, TabComp, fullW position: sticky; top: 0; background-color: var(--parent-bg-color); - z-index: 10; + z-index: ${Z_INDEX.localOverlay}; `, ]} > diff --git a/apps/web/src/component/common/tip/Tooltip.tsx b/apps/web/src/component/common/tip/Tooltip.tsx index d340a7a5..8cb8302b 100644 --- a/apps/web/src/component/common/tip/Tooltip.tsx +++ b/apps/web/src/component/common/tip/Tooltip.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { VariationPlacement } from "@popperjs/core"; import { OffsetModifier } from "@popperjs/core/lib/modifiers/offset"; @@ -166,11 +167,11 @@ function Content({ {asChild ? ( children ) : ( -
    context.setPopperEl(el)} style={{ ...styles.popper, zIndex: 100001 }} {...attributes.popper}> +
    context.setPopperEl(el)} style={{ ...styles.popper, zIndex: Z_INDEX.tooltip }} {...attributes.popper}>
    @@ -92,7 +93,7 @@ export function AnalysisContainer({ spaceId, retrospectId, hasAIAnalyzed }: Anal height: 3.4rem; background-color: transparent; border-radius: 0.6rem; - z-index: 1; + z-index: ${Z_INDEX.base}; position: relative; `} > diff --git a/apps/web/src/component/retrospect/space/RetrospectSpaceHeader.tsx b/apps/web/src/component/retrospect/space/RetrospectSpaceHeader.tsx index f785e844..798c9ca6 100644 --- a/apps/web/src/component/retrospect/space/RetrospectSpaceHeader.tsx +++ b/apps/web/src/component/retrospect/space/RetrospectSpaceHeader.tsx @@ -121,29 +121,27 @@ export default function RetrospectSpaceHeader() { )} - {isLeader && ( -
    - +
    + - - {spaceInfo?.formTag} - - -
    - )} + + {spaceInfo?.formTag} + + +
    diff --git a/apps/web/src/component/retrospect/space/actionItems/ActionItemAddSection.tsx b/apps/web/src/component/retrospect/space/actionItems/ActionItemAddSection.tsx index 33f72037..94914ba2 100644 --- a/apps/web/src/component/retrospect/space/actionItems/ActionItemAddSection.tsx +++ b/apps/web/src/component/retrospect/space/actionItems/ActionItemAddSection.tsx @@ -1,3 +1,5 @@ +import { Z_INDEX } from "@/style/zIndex"; +import { actionItemQueryKeys } from "@/hooks/api/actionItem/queryKeys"; import { Button, ButtonProvider } from "@/component/common/button"; import { TextArea } from "@/component/common/input"; import { Icon } from "@/component/common/Icon"; @@ -25,7 +27,7 @@ type ActionItemAddSectionProps = { export default function ActionItemAddSection({ spaceId, retrospectId, onClose, variant = "team" }: ActionItemAddSectionProps) { const queryClient = useQueryClient(); const isPersonal = variant === "personal"; - const actionItemQueryKey = isPersonal ? ["getPersonalActionItemListBySpace", spaceId] : ["getTeamActionItemList", spaceId]; + const actionItemQueryKey = isPersonal ? actionItemQueryKeys.personalBySpace(spaceId) : actionItemQueryKeys.team(spaceId); const { toast } = useToast(); const { data: retrospects } = useQuery(useApiOptionsGetRetrospects(spaceId)); @@ -189,7 +191,7 @@ export default function ActionItemAddSection({ spaceId, retrospectId, onClose, v background-color: white; border-radius: 0.8rem; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); - z-index: 10; + z-index: ${Z_INDEX.localOverlay}; overflow: hidden; padding: 0.6rem 0; diff --git a/apps/web/src/component/retrospect/space/actionItems/ActionItemsEditSection.tsx b/apps/web/src/component/retrospect/space/actionItems/ActionItemsEditSection.tsx index 6bb2a5a1..e3545af8 100644 --- a/apps/web/src/component/retrospect/space/actionItems/ActionItemsEditSection.tsx +++ b/apps/web/src/component/retrospect/space/actionItems/ActionItemsEditSection.tsx @@ -1,3 +1,4 @@ +import { actionItemQueryKeys } from "@/hooks/api/actionItem/queryKeys"; import { useState } from "react"; import { DragDropContext, Draggable, Droppable, DropResult } from "@hello-pangea/dnd"; @@ -37,7 +38,7 @@ const INIT_TEMP_ID = -1; export default function ActionItemsEditSection({ spaceId, retrospectId, todoList, onClose, variant = "team" }: ActionItemsEditSectionProps) { const queryClient = useQueryClient(); const isPersonal = variant === "personal"; - const actionItemQueryKey = isPersonal ? ["getPersonalActionItemListBySpace", spaceId] : ["getTeamActionItemList", spaceId]; + const actionItemQueryKey = isPersonal ? actionItemQueryKeys.personalBySpace(spaceId) : actionItemQueryKeys.team(spaceId); const listField = isPersonal ? "personalActionItemList" : "teamActionItemList"; const { toast } = useToast(); diff --git a/apps/web/src/component/retrospect/space/actionItems/ActionItemsTooltip.tsx b/apps/web/src/component/retrospect/space/actionItems/ActionItemsTooltip.tsx index ba429b77..9b51e8ee 100644 --- a/apps/web/src/component/retrospect/space/actionItems/ActionItemsTooltip.tsx +++ b/apps/web/src/component/retrospect/space/actionItems/ActionItemsTooltip.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { Typography } from "@/component/common/typography"; import { css } from "@emotion/react"; import { Icon } from "@/component/common/Icon"; @@ -22,7 +23,7 @@ export default function ActionItemsTooltip({ isVisible }: ActionItemsTooltipProp border-radius: 1.6rem; padding: 1.6rem 1.8rem; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12); - z-index: 1002; + z-index: ${Z_INDEX.contextual}; /* 말풍선 화살표 */ &::before { diff --git a/apps/web/src/component/retrospect/space/members/MemberManagement.tsx b/apps/web/src/component/retrospect/space/members/MemberManagement.tsx index 8dfc475d..be6ffa62 100644 --- a/apps/web/src/component/retrospect/space/members/MemberManagement.tsx +++ b/apps/web/src/component/retrospect/space/members/MemberManagement.tsx @@ -1,3 +1,4 @@ +import { spaceQueryKeys } from "@/hooks/api/space/queryKeys"; import React, { useState, useRef, useEffect } from "react"; import { css } from "@emotion/react"; import Cookies from "js-cookie"; @@ -91,9 +92,9 @@ export default function MemberManagement({ spaceId }: { spaceId: number }) { { onSuccess: () => { // 스페이스 정보를 리패치 - queryClient.invalidateQueries({ queryKey: ["spaces"] }); + queryClient.invalidateQueries({ queryKey: spaceQueryKeys.lists }); // 멤버 정보를 리패치 (혹여나 탈퇴하는 경우를 고려) - queryClient.invalidateQueries({ queryKey: ["getMembers", spaceId] }); + queryClient.invalidateQueries({ queryKey: spaceQueryKeys.members(spaceId) }); setCurrentView("main"); close(); }, diff --git a/apps/web/src/component/retrospect/space/members/MemberManagementDropdown.tsx b/apps/web/src/component/retrospect/space/members/MemberManagementDropdown.tsx index 45982171..72c0c2e4 100644 --- a/apps/web/src/component/retrospect/space/members/MemberManagementDropdown.tsx +++ b/apps/web/src/component/retrospect/space/members/MemberManagementDropdown.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import React from "react"; import { DESIGN_TOKEN_COLOR } from "@/style/designTokens"; import { css } from "@emotion/react"; @@ -17,7 +18,7 @@ export function MemberManagementDropdown({ children }: MemberManagementDropdownP background-color: ${DESIGN_TOKEN_COLOR.white}; border-radius: 1.2rem; box-shadow: 0 0.4rem 1.6rem rgba(0, 0, 0, 0.1); - z-index: 1000; + z-index: ${Z_INDEX.navigation}; min-width: 20rem; width: 28.8rem; max-height: 52rem; diff --git a/apps/web/src/component/retrospect/space/members/MemberManagementHeader.tsx b/apps/web/src/component/retrospect/space/members/MemberManagementHeader.tsx index c84b4973..0a61f256 100644 --- a/apps/web/src/component/retrospect/space/members/MemberManagementHeader.tsx +++ b/apps/web/src/component/retrospect/space/members/MemberManagementHeader.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import React from "react"; import { Typography } from "@/component/common/typography"; import { DESIGN_TOKEN_COLOR } from "@/style/designTokens"; @@ -98,7 +99,7 @@ const EditDropdown = React.forwardRef(({ onEd background-color: ${DESIGN_TOKEN_COLOR.white}; border-radius: 0.8rem; box-shadow: 0 0.4rem 1.6rem rgba(0, 0, 0, 0.1); - z-index: 1001; + z-index: ${Z_INDEX.sticky}; min-width: 12rem; border: 1px solid ${DESIGN_TOKEN_COLOR.gray200}; `} diff --git a/apps/web/src/component/retrospect/template/card/CardCarousel.tsx b/apps/web/src/component/retrospect/template/card/CardCarousel.tsx index 130028e0..515048a3 100644 --- a/apps/web/src/component/retrospect/template/card/CardCarousel.tsx +++ b/apps/web/src/component/retrospect/template/card/CardCarousel.tsx @@ -1,4 +1,5 @@ import { Swiper, SwiperSlide } from "swiper/react"; +import { css } from "@emotion/react"; import "swiper/css"; import "swiper/css/pagination"; @@ -15,6 +16,7 @@ import { PATHS } from "@layer/shared"; import { getDeviceType } from "@/utils/deviceUtils"; import { useFunnelModal } from "@/hooks/useFunnelModal"; import RecommendDone from "@/app/desktop/component/retrospect/template/recommend/Done"; +import { Z_INDEX } from "@/style/zIndex"; type CardCarouselProp = { spaceId?: number; @@ -75,6 +77,11 @@ export function CardCarousel({ templateId, spaceId, templateArr }: CardCarouselP swiper.autoplay.start(); }} className="card-carousel" + css={css` + & .animate { + z-index: ${Z_INDEX.activeSlide}; + } + `} > {templateArr.map((template, index) => ( diff --git a/apps/web/src/component/retrospect/template/card/TemplateCardManageToggleMenu.tsx b/apps/web/src/component/retrospect/template/card/TemplateCardManageToggleMenu.tsx index 37e53a24..7b410835 100644 --- a/apps/web/src/component/retrospect/template/card/TemplateCardManageToggleMenu.tsx +++ b/apps/web/src/component/retrospect/template/card/TemplateCardManageToggleMenu.tsx @@ -1,3 +1,4 @@ +import { retrospectQueryKeys } from "@/hooks/api/retrospect/queryKeys"; import { DesktopDateTimeInput } from "@/app/desktop/component/retrospectCreate/DesktopDateTimeInput"; import { ButtonProvider } from "@/component/common/button"; import { Icon } from "@/component/common/Icon"; @@ -225,7 +226,7 @@ export function ModifyRetrospect(props: { if (location.pathname === "/") { // 홈 화면에서 만약 수정을 할 경우에 모든 회고 목록을 invalidate 상태로 변경해줘요. await queryClient.invalidateQueries({ - queryKey: ["getAllRetrospects"], + queryKey: retrospectQueryKeys.all, }); } } diff --git a/apps/web/src/component/retrospect/template/card/swiper.css b/apps/web/src/component/retrospect/template/card/swiper.css index 8b491489..39bade00 100644 --- a/apps/web/src/component/retrospect/template/card/swiper.css +++ b/apps/web/src/component/retrospect/template/card/swiper.css @@ -23,7 +23,6 @@ transform: scale(1.2) !important; margin-right: 64px !important; margin-left: 48px; - z-index: 123123123; transition-delay: 1s !important; } diff --git a/apps/web/src/component/retrospect/template/list/CustomTemplateListItem.tsx b/apps/web/src/component/retrospect/template/list/CustomTemplateListItem.tsx index a6f0619b..c1ebc897 100644 --- a/apps/web/src/component/retrospect/template/list/CustomTemplateListItem.tsx +++ b/apps/web/src/component/retrospect/template/list/CustomTemplateListItem.tsx @@ -18,7 +18,8 @@ import { useModal } from "@/hooks/useModal"; import { useFunnelModal } from "@/hooks/useFunnelModal"; import CustomTemplateListDetailItem from "@/app/desktop/component/retrospect/template/list/CustomTemplateListDetailItem"; import { getDeviceType } from "@/utils/deviceUtils"; -import { TemplateListPageContext } from "@/app/mobile/retrospect/template/list/TemplateListPage"; +import { TemplateListPageContext as DesktopTemplateListPageContext } from "@/app/desktop/component/retrospect/template/list"; +import { TemplateListPageContext as MobileTemplateListPageContext } from "@/app/mobile/retrospect/template/list/TemplateListPage"; type CustomTemplateListItem = { id: number; @@ -35,13 +36,16 @@ export function CustomTemplateListItem({ id, title, tag, date }: CustomTemplateL const MENU_DELETE = "delete"; const SHEET_ID = `modifyTemplateSheet_${id}`; - const { spaceId, readOnly, isLeader } = useContext(TemplateListPageContext); + const { isDesktop } = getDeviceType(); + const desktopContext = useContext(DesktopTemplateListPageContext); + const mobileContext = useContext(MobileTemplateListPageContext); + const { spaceId, isLeader } = isDesktop ? desktopContext : mobileContext; + const readOnly = isDesktop ? true : mobileContext.readOnly; const { open } = useModal(); const { openBottomSheet, closeBottomSheet } = useBottomSheet(); const { value: templateTitle, handleInputChange: handleChangeTitle } = useInput(title); const { mutate: patchTemplateTitle } = usePatchTemplateTitle(+spaceId); const { mutate: deleteCustomTemplate } = useDeleteCustomTemplate(+spaceId); - const { isDesktop } = getDeviceType(); const handleSubmitTitle = () => { patchTemplateTitle({ formId: id, formTitle: templateTitle }); diff --git a/apps/web/src/component/retrospectCreate/customTemplate/ConfirmDefaultTemplate.tsx b/apps/web/src/component/retrospectCreate/customTemplate/ConfirmDefaultTemplate.tsx index 43d59f5b..4dccf016 100644 --- a/apps/web/src/component/retrospectCreate/customTemplate/ConfirmDefaultTemplate.tsx +++ b/apps/web/src/component/retrospectCreate/customTemplate/ConfirmDefaultTemplate.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useContext } from "react"; @@ -45,7 +46,7 @@ export function ConfirmDefaultTemplate({ goEdit }: ConfirmDefaultTemplateProps) gap: 1.2rem; position: relative; background-color: transparent; - z-index: 10; + z-index: ${Z_INDEX.localOverlay}; `} > {title} @@ -59,7 +60,7 @@ export function ConfirmDefaultTemplate({ goEdit }: ConfirmDefaultTemplateProps) right: 0; bottom: 0; margin: -1.2rem; - z-index: 9; + z-index: ${Z_INDEX.localUnderlay}; background: linear-gradient(to bottom, #fff 95%, transparent 100%); `} /> diff --git a/apps/web/src/component/retrospectCreate/customTemplate/ConfirmEditTemplate.tsx b/apps/web/src/component/retrospectCreate/customTemplate/ConfirmEditTemplate.tsx index 28c4a0fa..492fb302 100644 --- a/apps/web/src/component/retrospectCreate/customTemplate/ConfirmEditTemplate.tsx +++ b/apps/web/src/component/retrospectCreate/customTemplate/ConfirmEditTemplate.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useAtom } from "jotai"; import { useContext, useMemo, useRef } from "react"; @@ -23,15 +24,15 @@ type QuestionsListProps = { }; export function ConfirmEditTemplate({ goNext, goPrev }: QuestionsListProps) { - const { tag: originalTag } = useContext(TemplateContext); + const { title: originalTitle, tag: originalTag } = useContext(TemplateContext); const [retroCreateData, setRetroCreateData] = useAtom(retrospectCreateAtom); const tag = useMemo(() => { if (retroCreateData.hasChangedOriginal) { - return originalTag; + return "CUSTOM"; } - return "커스텀"; + return originalTag; }, [retroCreateData.hasChangedOriginal, originalTag]); - const { value: title, handleInputChange: handleTitleChange } = useInput(retroCreateData.formName); + const { value: title, handleInputChange: handleTitleChange } = useInput(retroCreateData.formName || originalTitle || "커스텀 템플릿"); const titleInputRef = useRef(null); const { toast } = useToast(); const { track } = useMixpanel(); @@ -75,7 +76,7 @@ export function ConfirmEditTemplate({ goNext, goPrev }: QuestionsListProps) { gap: 1.2rem; position: relative; background-color: transparent; - z-index: 10; + z-index: ${Z_INDEX.localOverlay}; `} >
    diff --git a/apps/web/src/component/retrospectCreate/customTemplate/EditQuestions.tsx b/apps/web/src/component/retrospectCreate/customTemplate/EditQuestions.tsx index 86ab1298..5f178bd3 100644 --- a/apps/web/src/component/retrospectCreate/customTemplate/EditQuestions.tsx +++ b/apps/web/src/component/retrospectCreate/customTemplate/EditQuestions.tsx @@ -75,6 +75,7 @@ export function EditQuestions({ goNext, goPrev }: EditQuestionsProps) { isNewForm: isEdited, hasChangedOriginal: !isDefaultExtended, questions: newQuestions, + formName: !isDefaultExtended ? "커스텀 템플릿" : prev.formName, })); }; diff --git a/apps/web/src/component/space/join/JoinLetter.tsx b/apps/web/src/component/space/join/JoinLetter.tsx index d470e112..a68a873b 100644 --- a/apps/web/src/component/space/join/JoinLetter.tsx +++ b/apps/web/src/component/space/join/JoinLetter.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useEffect, useState } from "react"; @@ -43,12 +44,12 @@ export function JoinLetter({ space, description, imgUrl, ...props }: JoinLetterP } #invite-card-top { - z-index: 1; + z-index: ${Z_INDEX.base}; top: 0.5rem; } #invite-card-content { - z-index: 2; + z-index: ${Z_INDEX.raised}; top: -10%; left: 0; right: 0; @@ -56,11 +57,11 @@ export function JoinLetter({ space, description, imgUrl, ...props }: JoinLetterP } #invite-card-bottom { - z-index: 3; + z-index: ${Z_INDEX.elevated}; } #invite-card-stamp { - z-index: 4; + z-index: ${Z_INDEX.foreground}; } @keyframes slideUp { @@ -137,7 +138,7 @@ export function JoinLetter({ space, description, imgUrl, ...props }: JoinLetterP height: 100%; position: absolute; bottom: 0; - z-index: -1; + z-index: ${Z_INDEX.behind}; background: ${DESIGN_TOKEN_COLOR.blue400}; `} >
    diff --git a/apps/web/src/component/space/view/ActionItemListView.tsx b/apps/web/src/component/space/view/ActionItemListView.tsx index 2b218ec1..a23ca5a5 100644 --- a/apps/web/src/component/space/view/ActionItemListView.tsx +++ b/apps/web/src/component/space/view/ActionItemListView.tsx @@ -1,3 +1,4 @@ +import { actionItemQueryKeys } from "@/hooks/api/actionItem/queryKeys"; import { css } from "@emotion/react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import Cookies from "js-cookie"; @@ -106,7 +107,7 @@ export function ActionItemListView({ isPossibleMake, teamActionList, spaceId, le if (spaceId) { await queryClient.invalidateQueries({ - queryKey: ["getTeamActionItemList", spaceId.toString()], + queryKey: actionItemQueryKeys.team(spaceId), }); } }, diff --git a/apps/web/src/component/space/view/RetrospectOptions.tsx b/apps/web/src/component/space/view/RetrospectOptions.tsx index 3aacecbe..c92ea6dd 100644 --- a/apps/web/src/component/space/view/RetrospectOptions.tsx +++ b/apps/web/src/component/space/view/RetrospectOptions.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { motion, AnimatePresence } from "framer-motion"; @@ -50,7 +51,7 @@ export function RetrospectOptions({ right: 0; background-color: white; border-radius: 1.2rem; - z-index: 10; + z-index: ${Z_INDEX.localOverlay}; width: 16.5rem; min-height: 9.2rem; height: fit-content; diff --git a/apps/web/src/component/space/view/SpaceAppBarRightComp.tsx b/apps/web/src/component/space/view/SpaceAppBarRightComp.tsx index 886d88ef..0243eca8 100644 --- a/apps/web/src/component/space/view/SpaceAppBarRightComp.tsx +++ b/apps/web/src/component/space/view/SpaceAppBarRightComp.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css, keyframes } from "@emotion/react"; import { motion, AnimatePresence } from "framer-motion"; import { useState, useEffect, useRef } from "react"; @@ -125,7 +126,7 @@ export function SpaceAppBarRightComp({ spaceId, onDeleteClick, isTooltipVisible, border: 1px solid #ccc; border-radius: 1rem; box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.1); - z-index: 99; + z-index: ${Z_INDEX.appBar}; width: 16.5rem; height: auto; padding: 0.3rem 2rem; diff --git a/apps/web/src/component/write/modal/EntireListModal.tsx b/apps/web/src/component/write/modal/EntireListModal.tsx index 2c92c323..a982a03b 100644 --- a/apps/web/src/component/write/modal/EntireListModal.tsx +++ b/apps/web/src/component/write/modal/EntireListModal.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useContext, useRef } from "react"; @@ -31,7 +32,7 @@ export function EntireListModal({ onClose, answers }: EntireListProps) { display: flex; justify-content: center; padding: 1.1rem 2rem; - z-index: 99999; + z-index: ${Z_INDEX.modal}; `} ref={containerRef} onClick={(e) => { diff --git a/apps/web/src/component/write/modal/TemporarySaveModal.tsx b/apps/web/src/component/write/modal/TemporarySaveModal.tsx index d02b1961..1c8396c4 100644 --- a/apps/web/src/component/write/modal/TemporarySaveModal.tsx +++ b/apps/web/src/component/write/modal/TemporarySaveModal.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useRef } from "react"; @@ -41,7 +42,7 @@ export function TemporarySaveModal({ justify-content: center; text-align: center; box-sizing: border-box; - z-index: 10001; + z-index: ${Z_INDEX.popover}; `} ref={containerRef} onClick={(e) => { diff --git a/apps/web/src/component/write/phase/Prepare.tsx b/apps/web/src/component/write/phase/Prepare.tsx index 05bfe32c..1b2d5729 100644 --- a/apps/web/src/component/write/phase/Prepare.tsx +++ b/apps/web/src/component/write/phase/Prepare.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useContext } from "react"; import { useNavigate } from "react-router-dom"; @@ -51,7 +52,7 @@ export function Prepare() { width: 100%; height: 40%; top: -5%; - z-index: 10000; + z-index: ${Z_INDEX.overlay}; transform: scale(1, -1); `} /> @@ -63,7 +64,7 @@ export function Prepare() { width: 100%; height: 60%; bottom: 0; - z-index: 10000; + z-index: ${Z_INDEX.overlay}; `} /> {/* NOTE: 추후 Flicking 캐러셀로 수정 */} diff --git a/apps/web/src/hooks/api/actionItem/queryKeys.ts b/apps/web/src/hooks/api/actionItem/queryKeys.ts new file mode 100644 index 00000000..50d0b688 --- /dev/null +++ b/apps/web/src/hooks/api/actionItem/queryKeys.ts @@ -0,0 +1,11 @@ +type QueryId = number | null | undefined; + +export const actionItemQueryKeys = { + personal: ["personalActionItemList"] as const, + member: (memberId: QueryId) => ["actionItemList", "member", memberId] as const, + space: (spaceId: QueryId) => ["actionItemList", "space", spaceId] as const, + team: (spaceId: QueryId) => ["getTeamActionItemList", spaceId] as const, + recentTeam: (spaceId: QueryId) => ["getRecentTeamActionItemList", spaceId] as const, + recentPersonal: (spaceId: QueryId) => ["getRecentPersonalActionItemList", spaceId] as const, + personalBySpace: (spaceId: QueryId) => ["getPersonalActionItemListBySpace", spaceId] as const, +}; diff --git a/apps/web/src/hooks/api/actionItem/useAPiOptionsRecentTeamActionList.ts b/apps/web/src/hooks/api/actionItem/useAPiOptionsRecentTeamActionList.ts index b6ee01ae..5b9e8ba7 100644 --- a/apps/web/src/hooks/api/actionItem/useAPiOptionsRecentTeamActionList.ts +++ b/apps/web/src/hooks/api/actionItem/useAPiOptionsRecentTeamActionList.ts @@ -1,3 +1,4 @@ +import { actionItemQueryKeys } from "@/hooks/api/actionItem/queryKeys"; import { UseQueryOptions } from "@tanstack/react-query"; import { api } from "@/api"; @@ -14,8 +15,8 @@ const getRecentTeamActionItemList = async (spaceId: number | undefined) => { export const useAPiOptionsRecentTeamActionList = ( spaceId?: number, -): UseQueryOptions => ({ - queryKey: ["getTeamActionItemList", spaceId!], +): UseQueryOptions> => ({ + queryKey: actionItemQueryKeys.recentTeam(spaceId), queryFn: () => getRecentTeamActionItemList(spaceId), select(data) { return data; diff --git a/apps/web/src/hooks/api/actionItem/useApiOptionsGetPersonalActionItemListBySpace.ts b/apps/web/src/hooks/api/actionItem/useApiOptionsGetPersonalActionItemListBySpace.ts index 42c28c80..47bc358c 100644 --- a/apps/web/src/hooks/api/actionItem/useApiOptionsGetPersonalActionItemListBySpace.ts +++ b/apps/web/src/hooks/api/actionItem/useApiOptionsGetPersonalActionItemListBySpace.ts @@ -1,3 +1,4 @@ +import { actionItemQueryKeys } from "@/hooks/api/actionItem/queryKeys"; import { queryOptions } from "@tanstack/react-query"; import { api } from "@/api"; @@ -10,7 +11,7 @@ const getPersonalActionItemListBySpace = async (spaceId: number) => { export const useApiOptionsGetPersonalActionItemListBySpace = (spaceId?: number) => queryOptions({ - queryKey: ["getPersonalActionItemListBySpace", spaceId] as const, + queryKey: actionItemQueryKeys.personalBySpace(spaceId), queryFn: () => { if (spaceId == null) throw new Error("spaceId is required"); return getPersonalActionItemListBySpace(spaceId); diff --git a/apps/web/src/hooks/api/actionItem/useApiOptionsGetRecentPersonalActionList.ts b/apps/web/src/hooks/api/actionItem/useApiOptionsGetRecentPersonalActionList.ts index 0deaf377..db7241f7 100644 --- a/apps/web/src/hooks/api/actionItem/useApiOptionsGetRecentPersonalActionList.ts +++ b/apps/web/src/hooks/api/actionItem/useApiOptionsGetRecentPersonalActionList.ts @@ -1,3 +1,4 @@ +import { actionItemQueryKeys } from "@/hooks/api/actionItem/queryKeys"; import { queryOptions } from "@tanstack/react-query"; import { api } from "@/api"; @@ -23,7 +24,7 @@ const getRecentPersonalActionItemList = async (spaceId: number) => { export const useApiOptionsGetRecentPersonalActionList = (spaceId?: number) => queryOptions({ - queryKey: ["getRecentPersonalActionItemList", spaceId] as const, + queryKey: actionItemQueryKeys.recentPersonal(spaceId), queryFn: () => { if (spaceId == null) throw new Error("spaceId is required"); return getRecentPersonalActionItemList(spaceId); diff --git a/apps/web/src/hooks/api/actionItem/useApiOptionsGetTeamActionItemList.ts b/apps/web/src/hooks/api/actionItem/useApiOptionsGetTeamActionItemList.ts index e438693a..95e26cb0 100644 --- a/apps/web/src/hooks/api/actionItem/useApiOptionsGetTeamActionItemList.ts +++ b/apps/web/src/hooks/api/actionItem/useApiOptionsGetTeamActionItemList.ts @@ -1,3 +1,4 @@ +import { actionItemQueryKeys } from "@/hooks/api/actionItem/queryKeys"; import { UseQueryOptions } from "@tanstack/react-query"; import { api } from "@/api"; @@ -10,8 +11,8 @@ const getTeamActionItemList = async (spaceId: number | undefined) => { export const useApiOptionsGetTeamActionItemList = ( spaceId?: number, -): UseQueryOptions => ({ - queryKey: ["getTeamActionItemList", spaceId!], +): UseQueryOptions> => ({ + queryKey: actionItemQueryKeys.team(spaceId), queryFn: () => getTeamActionItemList(spaceId), select(data) { return data; diff --git a/apps/web/src/hooks/api/actionItem/useGetActionItemList.ts b/apps/web/src/hooks/api/actionItem/useGetActionItemList.ts index d0db2f87..64c40867 100644 --- a/apps/web/src/hooks/api/actionItem/useGetActionItemList.ts +++ b/apps/web/src/hooks/api/actionItem/useGetActionItemList.ts @@ -1,3 +1,4 @@ +import { actionItemQueryKeys } from "@/hooks/api/actionItem/queryKeys"; import { useQuery, UseQueryOptions } from "@tanstack/react-query"; import { api } from "@/api"; @@ -17,7 +18,7 @@ export const useGetActionItemList = ({ return useQuery({ queryFn: () => getActionItemList(), - queryKey: [memberId], + queryKey: actionItemQueryKeys.member(memberId), ...options, }); }; diff --git a/apps/web/src/hooks/api/actionItem/useGetPersonalActionItemList.ts b/apps/web/src/hooks/api/actionItem/useGetPersonalActionItemList.ts index 53c5f466..1cac8580 100644 --- a/apps/web/src/hooks/api/actionItem/useGetPersonalActionItemList.ts +++ b/apps/web/src/hooks/api/actionItem/useGetPersonalActionItemList.ts @@ -1,3 +1,4 @@ +import { actionItemQueryKeys } from "@/hooks/api/actionItem/queryKeys"; import { useQuery, UseQueryOptions } from "@tanstack/react-query"; import { api } from "@/api"; @@ -21,7 +22,7 @@ export const useGetPersonalActionItemList = return useQuery({ queryFn: () => getPersonalActionItemList(), - queryKey: ["personalActionItemList"], + queryKey: actionItemQueryKeys.personal, ...options, }); }; diff --git a/apps/web/src/hooks/api/actionItem/useGetSpaceActionItemList.ts b/apps/web/src/hooks/api/actionItem/useGetSpaceActionItemList.ts index 4eecbcfa..4dc3fe8f 100644 --- a/apps/web/src/hooks/api/actionItem/useGetSpaceActionItemList.ts +++ b/apps/web/src/hooks/api/actionItem/useGetSpaceActionItemList.ts @@ -1,3 +1,4 @@ +import { actionItemQueryKeys } from "@/hooks/api/actionItem/queryKeys"; import { useQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -25,6 +26,6 @@ export const useGetSpaceActionItemList = ({ spaceId }: { spaceId: number }) => { return useQuery({ queryFn: () => getActionItemList(), - queryKey: [spaceId], + queryKey: actionItemQueryKeys.space(spaceId), }); }; diff --git a/apps/web/src/hooks/api/analysis/queryKeys.ts b/apps/web/src/hooks/api/analysis/queryKeys.ts new file mode 100644 index 00000000..82dd3bc7 --- /dev/null +++ b/apps/web/src/hooks/api/analysis/queryKeys.ts @@ -0,0 +1,7 @@ +type QueryId = number | null | undefined; + +export const analysisQueryKeys = { + member: ["myAnalysis"] as const, + result: (spaceId: QueryId, retrospectId: QueryId) => ["analysis", spaceId, retrospectId] as const, + answers: (spaceId: QueryId, retrospectId: QueryId) => ["analysisAnswers", spaceId, retrospectId] as const, +}; diff --git a/apps/web/src/hooks/api/analysis/useApiGetAnalysis.ts b/apps/web/src/hooks/api/analysis/useApiGetAnalysis.ts index 506ff007..996b2071 100644 --- a/apps/web/src/hooks/api/analysis/useApiGetAnalysis.ts +++ b/apps/web/src/hooks/api/analysis/useApiGetAnalysis.ts @@ -1,3 +1,4 @@ +import { analysisQueryKeys } from "@/hooks/api/analysis/queryKeys"; import { useQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -50,7 +51,7 @@ export const useApiGetAnalysis = ({ spaceId, retrospectId }: { spaceId: number; return useQuery({ queryFn: () => getAnalysis(), - queryKey: [spaceId, retrospectId], + queryKey: analysisQueryKeys.result(spaceId, retrospectId), retry: 1, }); }; diff --git a/apps/web/src/hooks/api/analysis/useApiGetMemberAnalysis.ts b/apps/web/src/hooks/api/analysis/useApiGetMemberAnalysis.ts index cab56235..c4c0cd9c 100644 --- a/apps/web/src/hooks/api/analysis/useApiGetMemberAnalysis.ts +++ b/apps/web/src/hooks/api/analysis/useApiGetMemberAnalysis.ts @@ -1,3 +1,4 @@ +import { analysisQueryKeys } from "@/hooks/api/analysis/queryKeys"; import { useQuery, UseQueryOptions } from "@tanstack/react-query"; import { api } from "@/api"; @@ -22,7 +23,7 @@ export const useApiGetMemberAnalysis = ({ options }: UseApiGetMemberAnalysisProp return useQuery({ queryFn: () => getAnalysis(), - queryKey: ["myAnalysis"], + queryKey: analysisQueryKeys.member, ...options, }); }; diff --git a/apps/web/src/hooks/api/auth/queryKeys.ts b/apps/web/src/hooks/api/auth/queryKeys.ts new file mode 100644 index 00000000..6ccd78ce --- /dev/null +++ b/apps/web/src/hooks/api/auth/queryKeys.ts @@ -0,0 +1,3 @@ +export const authQueryKeys = { + user: ["getUser"] as const, +}; diff --git a/apps/web/src/hooks/api/auth/useApiGetUser.ts b/apps/web/src/hooks/api/auth/useApiGetUser.ts index da541390..7eea9f91 100644 --- a/apps/web/src/hooks/api/auth/useApiGetUser.ts +++ b/apps/web/src/hooks/api/auth/useApiGetUser.ts @@ -1,3 +1,4 @@ +import { authQueryKeys } from "@/hooks/api/auth/queryKeys"; import { useSuspenseQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -10,7 +11,7 @@ export const useApiGetUser = () => { }; return useSuspenseQuery({ - queryKey: ["getUser"], + queryKey: authQueryKeys.user, queryFn: () => getUser(), }); }; diff --git a/apps/web/src/hooks/api/retrospect/analysis/useGetAnalysisAnswer.ts b/apps/web/src/hooks/api/retrospect/analysis/useGetAnalysisAnswer.ts index 07ed4320..2839498c 100644 --- a/apps/web/src/hooks/api/retrospect/analysis/useGetAnalysisAnswer.ts +++ b/apps/web/src/hooks/api/retrospect/analysis/useGetAnalysisAnswer.ts @@ -1,3 +1,4 @@ +import { analysisQueryKeys } from "@/hooks/api/analysis/queryKeys"; import { useQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -72,7 +73,7 @@ export const useGetAnalysisAnswer = ({ spaceId, retrospectId }: getAnalysisAnswe }; return useQuery({ queryFn: () => getAnalysisAnswer(), - queryKey: [spaceId, retrospectId, "analysis"], + queryKey: analysisQueryKeys.answers(spaceId, retrospectId), retry: 1, enabled: !!spaceId && !!retrospectId, }); diff --git a/apps/web/src/hooks/api/retrospect/close/useApiCloseRetrospect.ts b/apps/web/src/hooks/api/retrospect/close/useApiCloseRetrospect.ts index bb4c4354..c14e4a75 100644 --- a/apps/web/src/hooks/api/retrospect/close/useApiCloseRetrospect.ts +++ b/apps/web/src/hooks/api/retrospect/close/useApiCloseRetrospect.ts @@ -1,3 +1,4 @@ +import { retrospectQueryKeys } from "@/hooks/api/retrospect/queryKeys"; import { useMutation } from "@tanstack/react-query"; import { api } from "@/api"; @@ -18,7 +19,7 @@ export const useApiCloseRetrospect = () => { onSuccess: async (_, variable) => { toast.success("회고 마감이 완료되었어요"); await queryClient.invalidateQueries({ - queryKey: ["getRetrospects", variable.spaceId], + queryKey: retrospectQueryKeys.list(variable.spaceId), }); }, onError: () => { diff --git a/apps/web/src/hooks/api/retrospect/create/usePostRetrospectCreate.ts b/apps/web/src/hooks/api/retrospect/create/usePostRetrospectCreate.ts index 0be9063b..c7b62ea2 100644 --- a/apps/web/src/hooks/api/retrospect/create/usePostRetrospectCreate.ts +++ b/apps/web/src/hooks/api/retrospect/create/usePostRetrospectCreate.ts @@ -1,3 +1,4 @@ +import { retrospectQueryKeys } from "@/hooks/api/retrospect/queryKeys"; import { useMutation } from "@tanstack/react-query"; import { useResetAtom } from "jotai/utils"; import { useNavigate } from "react-router-dom"; @@ -37,7 +38,7 @@ export const usePostRetrospectCreate = (spaceId?: number) => { resetRetroCreateData(); queryClient.invalidateQueries({ - queryKey: ["getRetrospects", String(spaceId)], + queryKey: retrospectQueryKeys.list(spaceId), }); if (isMobile) { diff --git a/apps/web/src/hooks/api/retrospect/edit/usePatchRetrospect.ts b/apps/web/src/hooks/api/retrospect/edit/usePatchRetrospect.ts index 204a7b8b..2d27d9b7 100644 --- a/apps/web/src/hooks/api/retrospect/edit/usePatchRetrospect.ts +++ b/apps/web/src/hooks/api/retrospect/edit/usePatchRetrospect.ts @@ -1,3 +1,4 @@ +import { retrospectQueryKeys } from "@/hooks/api/retrospect/queryKeys"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { api } from "@/api"; @@ -24,8 +25,7 @@ export const usePatchRetrospect = () => { onSuccess: async (_, variable) => { toast.success("회고 정보가 수정되었어요!"); await queryClient.invalidateQueries({ - // TODO: queryKey 타입 재정의 필요 - queryKey: ["getRetrospects", variable.spaceId], + queryKey: retrospectQueryKeys.list(variable.spaceId), }); }, onError: () => { diff --git a/apps/web/src/hooks/api/retrospect/queryKeys.ts b/apps/web/src/hooks/api/retrospect/queryKeys.ts new file mode 100644 index 00000000..eb6bb5f1 --- /dev/null +++ b/apps/web/src/hooks/api/retrospect/queryKeys.ts @@ -0,0 +1,9 @@ +import type { RecommendTemplateType } from "@/types/retrospectCreate/recommend"; + +type QueryId = number | null | undefined; + +export const retrospectQueryKeys = { + all: ["getAllRetrospects"] as const, + list: (spaceId: QueryId) => ["getRetrospects", spaceId] as const, + recommendation: (recommendValue: RecommendTemplateType) => ["recommendTemplate", recommendValue] as const, +}; diff --git a/apps/web/src/hooks/api/retrospect/recommend/useApiRecommendTemplate.ts b/apps/web/src/hooks/api/retrospect/recommend/useApiRecommendTemplate.ts index bc3619a6..1c2819aa 100644 --- a/apps/web/src/hooks/api/retrospect/recommend/useApiRecommendTemplate.ts +++ b/apps/web/src/hooks/api/retrospect/recommend/useApiRecommendTemplate.ts @@ -1,3 +1,4 @@ +import { retrospectQueryKeys } from "@/hooks/api/retrospect/queryKeys"; import { useQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -24,7 +25,7 @@ export const useApiRecommendTemplate = (recommendValue: RecommendTemplateType) = }; return useQuery({ - queryKey: ["recommendTemplate", recommendValue], + queryKey: retrospectQueryKeys.recommendation(recommendValue), queryFn: () => recommendTemplate(recommendValue), staleTime: Infinity, }); diff --git a/apps/web/src/hooks/api/retrospect/useApiDeleteRetrospect.ts b/apps/web/src/hooks/api/retrospect/useApiDeleteRetrospect.ts index 63378884..7888ba14 100644 --- a/apps/web/src/hooks/api/retrospect/useApiDeleteRetrospect.ts +++ b/apps/web/src/hooks/api/retrospect/useApiDeleteRetrospect.ts @@ -1,3 +1,4 @@ +import { retrospectQueryKeys } from "@/hooks/api/retrospect/queryKeys"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { api } from "@/api"; @@ -17,9 +18,9 @@ export const useApiDeleteRetrospect = () => { mutationFn: ({ spaceId, retrospectId }: { spaceId: number | undefined; retrospectId: number | undefined }) => retrospectDelete(spaceId, retrospectId), onMutate: async (variables) => { - await queryClient.cancelQueries({ queryKey: ["getRetrospects", variables.spaceId] }); - const prevList = queryClient.getQueryData(["getRetrospects", variables.spaceId]); - queryClient.setQueryData(["getRetrospects", variables.spaceId], (old: RetrospectResponse) => { + await queryClient.cancelQueries({ queryKey: retrospectQueryKeys.list(variables.spaceId) }); + const prevList = queryClient.getQueryData(retrospectQueryKeys.list(variables.spaceId)); + queryClient.setQueryData(retrospectQueryKeys.list(variables.spaceId), (old: RetrospectResponse) => { return { ...old, retrospects: old?.retrospects?.filter((item) => item.retrospectId !== variables.retrospectId), @@ -30,10 +31,10 @@ export const useApiDeleteRetrospect = () => { onError: (error, variables, context) => { toast.error("회고 삭제 중 오류가 발생했어요, 다시 시도해주세요"); console.error("mutate error with", error); - queryClient.setQueryData(["getRetrospects", variables.spaceId], context?.prevList); + queryClient.setQueryData(retrospectQueryKeys.list(variables.spaceId), context?.prevList); }, onSettled: async (_, __, variables) => { - await queryClient.invalidateQueries({ queryKey: ["getRetrospects", variables.spaceId] }); + await queryClient.invalidateQueries({ queryKey: retrospectQueryKeys.list(variables.spaceId) }); }, onSuccess: () => { toast.success("회고 삭제가 완료되었어요"); diff --git a/apps/web/src/hooks/api/retrospect/useApiOptionsGetRetrospects.ts b/apps/web/src/hooks/api/retrospect/useApiOptionsGetRetrospects.ts index 7d047e78..5244d7a7 100644 --- a/apps/web/src/hooks/api/retrospect/useApiOptionsGetRetrospects.ts +++ b/apps/web/src/hooks/api/retrospect/useApiOptionsGetRetrospects.ts @@ -1,3 +1,4 @@ +import { retrospectQueryKeys } from "@/hooks/api/retrospect/queryKeys"; import { UseQueryOptions, useQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -19,7 +20,7 @@ const getAllRetrospectsFetch = async () => { }; export const useApiOptionsGetRetrospects = (spaceId?: number): UseQueryOptions => ({ - queryKey: ["getRetrospects", spaceId], + queryKey: retrospectQueryKeys.list(spaceId), queryFn: () => spaceRetrospectFetch(spaceId), select(data) { return data.retrospects; @@ -30,7 +31,7 @@ export const useApiOptionsGetRetrospects = (spaceId?: number): UseQueryOptions>) => { return useQuery({ - queryKey: ["getAllRetrospects"], + queryKey: retrospectQueryKeys.all, queryFn: getAllRetrospectsFetch, select: (data) => data.retrospects, ...options, diff --git a/apps/web/src/hooks/api/space/members/useApiChangeLeader.ts b/apps/web/src/hooks/api/space/members/useApiChangeLeader.ts index aa751d9c..c641d638 100644 --- a/apps/web/src/hooks/api/space/members/useApiChangeLeader.ts +++ b/apps/web/src/hooks/api/space/members/useApiChangeLeader.ts @@ -1,3 +1,4 @@ +import { spaceQueryKeys } from "@/hooks/api/space/queryKeys"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { api } from "@/api"; @@ -18,7 +19,7 @@ export const useChangeLeader = (spaceId: number) => { mutationFn: (changeValue: { spaceId: number; memberId: number }) => changeLeader(changeValue), onSuccess: async () => { await queryClient.invalidateQueries({ - queryKey: ["getMembers", spaceId], + queryKey: spaceQueryKeys.members(spaceId), }); toast.success("대표자가 변경되었습니다."); }, diff --git a/apps/web/src/hooks/api/space/members/useApiGetMembers.ts b/apps/web/src/hooks/api/space/members/useApiGetMembers.ts index d9f59611..a35db4c4 100644 --- a/apps/web/src/hooks/api/space/members/useApiGetMembers.ts +++ b/apps/web/src/hooks/api/space/members/useApiGetMembers.ts @@ -1,3 +1,4 @@ +import { spaceQueryKeys } from "@/hooks/api/space/queryKeys"; import { useQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -16,7 +17,7 @@ export const useApiGetMemers = (spaceId: number) => { }; return useQuery({ - queryKey: ["getMembers", spaceId], + queryKey: spaceQueryKeys.members(spaceId), queryFn: () => getMembers(spaceId), }); }; diff --git a/apps/web/src/hooks/api/space/members/useApiKickMembers.ts b/apps/web/src/hooks/api/space/members/useApiKickMembers.ts index 30614194..3d3c57ab 100644 --- a/apps/web/src/hooks/api/space/members/useApiKickMembers.ts +++ b/apps/web/src/hooks/api/space/members/useApiKickMembers.ts @@ -1,3 +1,4 @@ +import { spaceQueryKeys } from "@/hooks/api/space/queryKeys"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { api } from "@/api"; @@ -16,10 +17,10 @@ export const useApiKickMember = (spaceId: number) => { mutationFn: (deleteValue: { spaceId: number; memberId: number }) => apiKickMember(deleteValue), onSuccess: async () => { await queryClient.invalidateQueries({ - queryKey: ["getMembers", spaceId], + queryKey: spaceQueryKeys.members(spaceId), }); await queryClient.invalidateQueries({ - queryKey: ["getSpaceInfo", spaceId], + queryKey: spaceQueryKeys.info(spaceId), }); toast.success("해당 팀원을 추방시켰습니다."); }, diff --git a/apps/web/src/hooks/api/space/queryKeys.ts b/apps/web/src/hooks/api/space/queryKeys.ts new file mode 100644 index 00000000..cefdef48 --- /dev/null +++ b/apps/web/src/hooks/api/space/queryKeys.ts @@ -0,0 +1,9 @@ +type QueryId = number | null | undefined; + +export const spaceQueryKeys = { + lists: ["spaces"] as const, + list: (category: string) => [...spaceQueryKeys.lists, category] as const, + detail: (spaceId: QueryId) => ["getSpace", spaceId] as const, + info: (spaceId: QueryId) => ["getSpaceInfo", spaceId] as const, + members: (spaceId: QueryId) => ["getMembers", spaceId] as const, +}; diff --git a/apps/web/src/hooks/api/space/useApiGetSpace.ts b/apps/web/src/hooks/api/space/useApiGetSpace.ts index f490806c..b3964385 100644 --- a/apps/web/src/hooks/api/space/useApiGetSpace.ts +++ b/apps/web/src/hooks/api/space/useApiGetSpace.ts @@ -1,3 +1,4 @@ +import { spaceQueryKeys } from "@/hooks/api/space/queryKeys"; import { useQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -28,7 +29,7 @@ export const useApiGetSpace = (spaceId: number, isPublic: boolean = false, optio }; return useQuery({ - queryKey: ["getSpace", spaceId], + queryKey: spaceQueryKeys.detail(spaceId), queryFn: () => getSpace(spaceId, isPublic), enabled: options?.enabled ?? true, }); diff --git a/apps/web/src/hooks/api/space/useApiGetSpaceList.ts b/apps/web/src/hooks/api/space/useApiGetSpaceList.ts index 92e0ad67..5eb2b089 100644 --- a/apps/web/src/hooks/api/space/useApiGetSpaceList.ts +++ b/apps/web/src/hooks/api/space/useApiGetSpaceList.ts @@ -1,3 +1,4 @@ +import { spaceQueryKeys } from "@/hooks/api/space/queryKeys"; import { useInfiniteQuery, UseInfiniteQueryOptions } from "@tanstack/react-query"; import { api } from "@/api"; @@ -37,7 +38,7 @@ export const useApiGetSpaceList = (category: string, options?: UseApiGetSpaceLis const { pageSize = DEFAULT_PAGE_SIZE, ...queryOptions } = options || {}; return useInfiniteQuery({ - queryKey: ["spaces", category], + queryKey: spaceQueryKeys.list(category), queryFn: ({ pageParam = 0 }) => { return spaceFetch(pageParam as number, category, pageSize); }, diff --git a/apps/web/src/hooks/api/space/useApiLeaveSpace.ts b/apps/web/src/hooks/api/space/useApiLeaveSpace.ts index 99f39890..6075daf6 100644 --- a/apps/web/src/hooks/api/space/useApiLeaveSpace.ts +++ b/apps/web/src/hooks/api/space/useApiLeaveSpace.ts @@ -1,3 +1,4 @@ +import { spaceQueryKeys } from "@/hooks/api/space/queryKeys"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { useNavigate } from "react-router-dom"; @@ -19,7 +20,7 @@ export const useApiLeaveSpace = () => { mutationFn: (spaceId: number) => apiSpaceLeave(spaceId), onSuccess: () => { navigate(PATHS.home()); - queryClient.invalidateQueries({ queryKey: ["spaces"] }); + queryClient.invalidateQueries({ queryKey: spaceQueryKeys.lists }); toast.success("스페이스를 성공적으로 떠났습니다."); }, onError: (error) => { diff --git a/apps/web/src/hooks/api/space/useApiOptionsGetSpaceInfo.ts b/apps/web/src/hooks/api/space/useApiOptionsGetSpaceInfo.ts index 6ac8421f..adb033de 100644 --- a/apps/web/src/hooks/api/space/useApiOptionsGetSpaceInfo.ts +++ b/apps/web/src/hooks/api/space/useApiOptionsGetSpaceInfo.ts @@ -1,3 +1,4 @@ +import { spaceQueryKeys } from "@/hooks/api/space/queryKeys"; import { UseQueryOptions } from "@tanstack/react-query"; import { api } from "@/api"; @@ -8,8 +9,8 @@ const spaceInfoFetch = async (spaceId: number | undefined) => { return response.data; }; -export const useApiOptionsGetSpaceInfo = (spaceId?: number): UseQueryOptions => ({ - queryKey: ["getSpaceInfo", spaceId!], +export const useApiOptionsGetSpaceInfo = (spaceId?: number): UseQueryOptions> => ({ + queryKey: spaceQueryKeys.info(spaceId), queryFn: () => spaceInfoFetch(spaceId), enabled: !!spaceId, }); diff --git a/apps/web/src/hooks/api/space/useGetSpace.ts b/apps/web/src/hooks/api/space/useGetSpace.ts index 7c1fef9a..4e90ee64 100644 --- a/apps/web/src/hooks/api/space/useGetSpace.ts +++ b/apps/web/src/hooks/api/space/useGetSpace.ts @@ -1,3 +1,4 @@ +import { spaceQueryKeys } from "@/hooks/api/space/queryKeys"; import { useQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -10,7 +11,7 @@ export const useApiGetSpacePrivate = (spaceId: number) => { }; return useQuery({ - queryKey: ["getSpace", spaceId], + queryKey: spaceQueryKeys.detail(spaceId), queryFn: getSpace, refetchOnWindowFocus: false, }); diff --git a/apps/web/src/hooks/api/template/queryKeys.ts b/apps/web/src/hooks/api/template/queryKeys.ts new file mode 100644 index 00000000..a45bdcc3 --- /dev/null +++ b/apps/web/src/hooks/api/template/queryKeys.ts @@ -0,0 +1,9 @@ +type QueryId = number | null | undefined; + +export const templateQueryKeys = { + defaultList: ["getDefaultTemplates"] as const, + customList: (spaceId: QueryId) => ["getCustomTemplateList", spaceId] as const, + custom: (formId: QueryId) => ["customTemplate", formId] as const, + detail: (templateId: QueryId) => ["templateInfo", templateId] as const, + simpleDetail: (templateId: QueryId) => ["simpleTemplateInfo", templateId] as const, +}; diff --git a/apps/web/src/hooks/api/template/useDeleteCustomTemplate.ts b/apps/web/src/hooks/api/template/useDeleteCustomTemplate.ts index 56734e4a..2fea43eb 100644 --- a/apps/web/src/hooks/api/template/useDeleteCustomTemplate.ts +++ b/apps/web/src/hooks/api/template/useDeleteCustomTemplate.ts @@ -1,3 +1,4 @@ +import { templateQueryKeys } from "@/hooks/api/template/queryKeys"; import { InfiniteData, useMutation, useQueryClient } from "@tanstack/react-query"; import { api } from "@/api"; @@ -16,9 +17,9 @@ export const useDeleteCustomTemplate = (spaceId: number) => { return useMutation({ mutationFn: deleteCustomTemplate, onMutate: async (newTemplate) => { - await queryClient.cancelQueries({ queryKey: ["getCustomTemplateList", spaceId] }); - const prevList = queryClient.getQueryData(["getCustomTemplateList", spaceId]); - queryClient.setQueryData(["getCustomTemplateList", spaceId], (old: InfiniteData) => { + await queryClient.cancelQueries({ queryKey: templateQueryKeys.customList(spaceId) }); + const prevList = queryClient.getQueryData(templateQueryKeys.customList(spaceId)); + queryClient.setQueryData(templateQueryKeys.customList(spaceId), (old: InfiniteData) => { return { ...old, pages: old.pages.map((page) => ({ @@ -31,14 +32,14 @@ export const useDeleteCustomTemplate = (spaceId: number) => { }, onError: (error, _, context) => { console.error("mutate error with", error); - queryClient.setQueryData(["getCustomTemplateList", spaceId], context?.prevList); + queryClient.setQueryData(templateQueryKeys.customList(spaceId), context?.prevList); }, onSettled: async () => { - await queryClient.invalidateQueries({ queryKey: ["getCustomTemplateList", spaceId] }); + await queryClient.invalidateQueries({ queryKey: templateQueryKeys.customList(spaceId) }); }, onSuccess: async () => { await queryClient.invalidateQueries({ - queryKey: ["getCustomTemplateList", spaceId], //FIXME - query key 상수화 + queryKey: templateQueryKeys.customList(spaceId), }); }, }); diff --git a/apps/web/src/hooks/api/template/useGetCustomTemplate.ts b/apps/web/src/hooks/api/template/useGetCustomTemplate.ts index 0da09187..9256f496 100644 --- a/apps/web/src/hooks/api/template/useGetCustomTemplate.ts +++ b/apps/web/src/hooks/api/template/useGetCustomTemplate.ts @@ -1,3 +1,4 @@ +import { templateQueryKeys } from "@/hooks/api/template/queryKeys"; import { useSuspenseQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -10,7 +11,7 @@ export const useGetCustomTemplate = (formId: number) => { }; return useSuspenseQuery({ - queryKey: ["customTemplate", formId], + queryKey: templateQueryKeys.custom(formId), queryFn: getCustomTemplate, }); }; diff --git a/apps/web/src/hooks/api/template/useGetCustomTemplateList.ts b/apps/web/src/hooks/api/template/useGetCustomTemplateList.ts index 916da7b1..1bc85ef4 100644 --- a/apps/web/src/hooks/api/template/useGetCustomTemplateList.ts +++ b/apps/web/src/hooks/api/template/useGetCustomTemplateList.ts @@ -1,3 +1,4 @@ +import { templateQueryKeys } from "@/hooks/api/template/queryKeys"; import { useSuspenseInfiniteQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -15,7 +16,7 @@ export const useGetCustomTemplateList = (spaceId: number) => { }; return useSuspenseInfiniteQuery({ - queryKey: ["getCustomTemplateList", spaceId], + queryKey: templateQueryKeys.customList(spaceId), queryFn: ({ pageParam }) => getCustomTemplateList(pageParam as number).then((res) => res.customTemplateList), initialPageParam: 0, getNextPageParam: (lastPage) => (lastPage.last ? undefined : lastPage.pageable.pageNumber + 1), diff --git a/apps/web/src/hooks/api/template/useGetDefaultTemplateList.ts b/apps/web/src/hooks/api/template/useGetDefaultTemplateList.ts index d429657b..156df905 100644 --- a/apps/web/src/hooks/api/template/useGetDefaultTemplateList.ts +++ b/apps/web/src/hooks/api/template/useGetDefaultTemplateList.ts @@ -1,3 +1,4 @@ +import { templateQueryKeys } from "@/hooks/api/template/queryKeys"; import { useSuspenseQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -10,7 +11,7 @@ export const useGetDefaultTemplateList = () => { }; return useSuspenseQuery({ - queryKey: ["getDefaultTemplates"], + queryKey: templateQueryKeys.defaultList, queryFn: getDefaultTemplateList, }); }; diff --git a/apps/web/src/hooks/api/template/useGetSimpleTemplateInfo.ts b/apps/web/src/hooks/api/template/useGetSimpleTemplateInfo.ts index b0fd63d9..15c39bb7 100644 --- a/apps/web/src/hooks/api/template/useGetSimpleTemplateInfo.ts +++ b/apps/web/src/hooks/api/template/useGetSimpleTemplateInfo.ts @@ -1,3 +1,4 @@ +import { templateQueryKeys } from "@/hooks/api/template/queryKeys"; import { useSuspenseQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -17,7 +18,7 @@ export const useGetSimpleTemplateInfo = (templateId: number) => { return useSuspenseQuery({ queryFn: () => getSimpleTemplateInfo(), - queryKey: ["simpleTemplateInfo", templateId], + queryKey: templateQueryKeys.simpleDetail(templateId), refetchOnWindowFocus: false, }); }; diff --git a/apps/web/src/hooks/api/template/useGetTemplateInfo.ts b/apps/web/src/hooks/api/template/useGetTemplateInfo.ts index e8b5c5bf..b9a6ff92 100644 --- a/apps/web/src/hooks/api/template/useGetTemplateInfo.ts +++ b/apps/web/src/hooks/api/template/useGetTemplateInfo.ts @@ -1,3 +1,4 @@ +import { templateQueryKeys } from "@/hooks/api/template/queryKeys"; import { useSuspenseQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -33,7 +34,7 @@ export const useGetTemplateInfo = ({ templateId }: { templateId: number }) => { return useSuspenseQuery({ queryFn: () => getTemplateInfo(), - queryKey: ["templateInfo", templateId], + queryKey: templateQueryKeys.detail(templateId), refetchOnWindowFocus: false, }); }; diff --git a/apps/web/src/hooks/api/template/usePatchTemplateTitle.ts b/apps/web/src/hooks/api/template/usePatchTemplateTitle.ts index f63ee74a..81255c57 100644 --- a/apps/web/src/hooks/api/template/usePatchTemplateTitle.ts +++ b/apps/web/src/hooks/api/template/usePatchTemplateTitle.ts @@ -1,3 +1,4 @@ +import { templateQueryKeys } from "@/hooks/api/template/queryKeys"; import { InfiniteData, useMutation, useQueryClient } from "@tanstack/react-query"; import { api } from "@/api"; @@ -16,9 +17,9 @@ export const usePatchTemplateTitle = (spaceId: number) => { return useMutation({ mutationFn: patchTemplateTitle, onMutate: async (newTemplate) => { - await queryClient.cancelQueries({ queryKey: ["getCustomTemplateList", spaceId] }); - const prevList = queryClient.getQueryData(["getCustomTemplateList", spaceId]); - queryClient.setQueryData(["getCustomTemplateList", spaceId], (old: InfiniteData) => { + await queryClient.cancelQueries({ queryKey: templateQueryKeys.customList(spaceId) }); + const prevList = queryClient.getQueryData(templateQueryKeys.customList(spaceId)); + queryClient.setQueryData(templateQueryKeys.customList(spaceId), (old: InfiniteData) => { return { ...old, pages: old.pages.map((page) => ({ @@ -32,10 +33,10 @@ export const usePatchTemplateTitle = (spaceId: number) => { }, onError: (error, _, context) => { console.error("mutate error with", error); - queryClient.setQueryData(["getCustomTemplateList", spaceId], context?.prevList); + queryClient.setQueryData(templateQueryKeys.customList(spaceId), context?.prevList); }, onSettled: async () => { - await queryClient.invalidateQueries({ queryKey: ["getCustomTemplateList", spaceId] }); + await queryClient.invalidateQueries({ queryKey: templateQueryKeys.customList(spaceId) }); }, }); }; diff --git a/apps/web/src/hooks/api/template/usePostRecentTemplateId.ts b/apps/web/src/hooks/api/template/usePostRecentTemplateId.ts index f9e72eb9..2c9139f7 100644 --- a/apps/web/src/hooks/api/template/usePostRecentTemplateId.ts +++ b/apps/web/src/hooks/api/template/usePostRecentTemplateId.ts @@ -1,3 +1,4 @@ +import { spaceQueryKeys } from "@/hooks/api/space/queryKeys"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { api } from "@/api"; @@ -16,7 +17,7 @@ export const usePostRecentTemplateId = (spaceId: number) => { mutationFn: postRecentTemplateId, onSuccess: async () => { await queryClient.invalidateQueries({ - queryKey: ["getSpaceInfo", String(spaceId)], //FIXME - query key 상수화 + queryKey: spaceQueryKeys.info(spaceId), }); }, }); diff --git a/apps/web/src/hooks/api/write/queryKeys.ts b/apps/web/src/hooks/api/write/queryKeys.ts new file mode 100644 index 00000000..155f0975 --- /dev/null +++ b/apps/web/src/hooks/api/write/queryKeys.ts @@ -0,0 +1,8 @@ +type QueryId = number | null | undefined; + +export const writeQueryKeys = { + questions: (spaceId: QueryId, retrospectId: QueryId) => ["questions", spaceId, retrospectId] as const, + temporaryQuestions: (spaceId: QueryId, retrospectId: QueryId) => + ["temporaryQuestion", spaceId, retrospectId] as const, + answers: (spaceId: QueryId, retrospectId: QueryId) => ["answers", spaceId, retrospectId] as const, +}; diff --git a/apps/web/src/hooks/api/write/useGetAnswers.ts b/apps/web/src/hooks/api/write/useGetAnswers.ts index e359fa9a..237677dc 100644 --- a/apps/web/src/hooks/api/write/useGetAnswers.ts +++ b/apps/web/src/hooks/api/write/useGetAnswers.ts @@ -1,3 +1,4 @@ +import { writeQueryKeys } from "@/hooks/api/write/queryKeys"; import { useQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -36,7 +37,7 @@ export const useGetAnswers = ({ spaceId, retrospectId }: { spaceId: number; retr }; return useQuery({ - queryKey: ["answers", spaceId, retrospectId], + queryKey: writeQueryKeys.answers(spaceId, retrospectId), queryFn: () => getQuestions(), refetchOnWindowFocus: false, retry: 1, diff --git a/apps/web/src/hooks/api/write/useGetQuestions.ts b/apps/web/src/hooks/api/write/useGetQuestions.ts index 44415511..2971a6d7 100644 --- a/apps/web/src/hooks/api/write/useGetQuestions.ts +++ b/apps/web/src/hooks/api/write/useGetQuestions.ts @@ -1,3 +1,4 @@ +import { writeQueryKeys } from "@/hooks/api/write/queryKeys"; import { useQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -25,7 +26,7 @@ export const useGetQuestions = ({ spaceId, retrospectId }: { spaceId: number; re }; return useQuery({ - queryKey: ["questions", spaceId, retrospectId], + queryKey: writeQueryKeys.questions(spaceId, retrospectId), queryFn: () => getQuestions(), }); }; diff --git a/apps/web/src/hooks/api/write/useGetTemporaryQuestions.ts b/apps/web/src/hooks/api/write/useGetTemporaryQuestions.ts index dee27d29..ad755339 100644 --- a/apps/web/src/hooks/api/write/useGetTemporaryQuestions.ts +++ b/apps/web/src/hooks/api/write/useGetTemporaryQuestions.ts @@ -1,3 +1,4 @@ +import { writeQueryKeys } from "@/hooks/api/write/queryKeys"; import { useQuery } from "@tanstack/react-query"; import { api } from "@/api"; @@ -20,7 +21,7 @@ export const useGetTemporaryQuestions = ({ spaceId, retrospectId }: { spaceId: n }; return useQuery({ - queryKey: ["temporaryQuestion", spaceId, retrospectId], + queryKey: writeQueryKeys.temporaryQuestions(spaceId, retrospectId), queryFn: () => getTemporaryQuestions(), refetchOnWindowFocus: false, retry: 1, diff --git a/apps/web/src/hooks/app/space/useModifySpace.ts b/apps/web/src/hooks/app/space/useModifySpace.ts index 4f65c427..4939170b 100644 --- a/apps/web/src/hooks/app/space/useModifySpace.ts +++ b/apps/web/src/hooks/app/space/useModifySpace.ts @@ -1,3 +1,4 @@ +import { spaceQueryKeys } from "@/hooks/api/space/queryKeys"; import { api } from "@/api"; import { useApiEditSpace } from "@/hooks/api/space/edit/useApiEditSpace"; import { useApiDeleteSpace } from "@/hooks/api/space/useApiDeleteSpace"; @@ -80,12 +81,12 @@ export default function useModifySpace({ id }: ModifySpaceProps) { setterCurrentSpace((prev) => ({ ...prev, ...{ name, introduction } }) as Space); // 수정이 성공하면 현재 스페이스 정보를 상세 조회하는 쿼리를 리패치 queryClient.invalidateQueries({ - queryKey: ["getSpace", id], + queryKey: spaceQueryKeys.detail(id), }); } // 수정이나 삭제가 성공하면 스페이스 목록과 현재 스페이스 정보를 리패치 queryClient.invalidateQueries({ - queryKey: ["spaces"], + queryKey: spaceQueryKeys.lists, }); } }, [isEditSuccess, isDeleteSuccess]); diff --git a/apps/web/src/hooks/useFunnelModal.ts b/apps/web/src/hooks/useFunnelModal.ts index 9fb903b2..5479a258 100644 --- a/apps/web/src/hooks/useFunnelModal.ts +++ b/apps/web/src/hooks/useFunnelModal.ts @@ -7,7 +7,7 @@ export const useFunnelModal = () => { const [state, setState] = useAtom(FunnelModalState); const openFunnelModal = useCallback( - ({ title, step, contents, templateTag, onConfirm, onClose, onPrevious, overlayIndex = 10000 }: Omit) => { + ({ title, step, contents, templateTag, onConfirm, onClose, onPrevious, overlayIndex = 10000, options }: Omit) => { setState({ isOpen: true, title, @@ -18,6 +18,11 @@ export const useFunnelModal = () => { onClose, onPrevious, overlayIndex, + options: { + previousButton: true, + quitButton: true, + ...options, + }, }); }, [setState], @@ -34,6 +39,10 @@ export const useFunnelModal = () => { onConfirm: () => {}, onPrevious: () => {}, overlayIndex: 10000, + options: { + previousButton: true, + quitButton: true, + }, }); }, [setState]); diff --git a/apps/web/src/layout/DualToneLayout.tsx b/apps/web/src/layout/DualToneLayout.tsx index 1e2d3fe6..c8020952 100644 --- a/apps/web/src/layout/DualToneLayout.tsx +++ b/apps/web/src/layout/DualToneLayout.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { ReactNode, useEffect, useRef, useState } from "react"; @@ -39,7 +40,7 @@ export function DualToneLayout({ top: 0; width: 100%; max-width: 48rem; - z-index: 999; + z-index: ${Z_INDEX.sheetContent}; `} > diff --git a/apps/web/src/lib/provider/bridge-provider.tsx b/apps/web/src/lib/provider/bridge-provider.tsx index d6b3cf78..5b753f73 100644 --- a/apps/web/src/lib/provider/bridge-provider.tsx +++ b/apps/web/src/lib/provider/bridge-provider.tsx @@ -9,6 +9,10 @@ import { createContext } from "@/lib/create-context"; const BRIDGE_PROVIER = "BRIDGE_PROVIER"; +const bridgeQueryKeys = { + safeAreaHeight: ["app", "height"] as const, +}; + type AppBridgeState = { getSafeAreaHeight: () => Promise; checkWebview: () => Promise; @@ -35,7 +39,7 @@ const [Provider, useBridge] = createContext(BRIDGE_PROVIER const BridgeProvider = ({ children }: PropsWithChildren) => { const bridgeRef = useRef(bridge).current; const { data: { safeAreaHeight, isWebViewBridgeAvailable } = {} } = useQuery({ - queryKey: ["app", "height"], + queryKey: bridgeQueryKeys.safeAreaHeight, queryFn: async () => { const safeAreaHeight = await bridge.getSafeAreaHeight(); diff --git a/apps/web/src/lib/provider/offline-provider.tsx b/apps/web/src/lib/provider/offline-provider.tsx index 7bd6247c..d5f8cbd3 100644 --- a/apps/web/src/lib/provider/offline-provider.tsx +++ b/apps/web/src/lib/provider/offline-provider.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useEffect, useState } from "react"; @@ -27,7 +28,7 @@ export function OfflineBanner() { css={css` position: fixed; inset: 0; - z-index: 99999; + z-index: ${Z_INDEX.modal}; background: #ffffff; display: flex; flex-direction: column; diff --git a/apps/web/src/lib/provider/pwa-update-provider.tsx b/apps/web/src/lib/provider/pwa-update-provider.tsx index 465e9f0d..dfde7ec5 100644 --- a/apps/web/src/lib/provider/pwa-update-provider.tsx +++ b/apps/web/src/lib/provider/pwa-update-provider.tsx @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { css } from "@emotion/react"; import { useRegisterSW } from "virtual:pwa-register/react"; @@ -16,7 +17,7 @@ export function PWAUpdatePrompt() { bottom: 2.4rem; left: 50%; transform: translateX(-50%); - z-index: 9999; + z-index: ${Z_INDEX.notification}; display: flex; align-items: center; gap: 1.2rem; diff --git a/apps/web/src/store/modal/funnelModalAtom.ts b/apps/web/src/store/modal/funnelModalAtom.ts index 4e2edd31..bccd7fdd 100644 --- a/apps/web/src/store/modal/funnelModalAtom.ts +++ b/apps/web/src/store/modal/funnelModalAtom.ts @@ -1,3 +1,4 @@ +import { Z_INDEX } from "@/style/zIndex"; import { FunnelModalType } from "@/types/modal"; import { atom } from "jotai"; @@ -10,5 +11,9 @@ export const FunnelModalState = atom({ onClose: () => {}, onConfirm: () => {}, onPrevious: () => {}, - overlayIndex: 10000, + options: { + quitButton: true, + previousButton: true, + }, + overlayIndex: Z_INDEX.overlay, }); diff --git a/apps/web/src/style/zIndex.ts b/apps/web/src/style/zIndex.ts new file mode 100644 index 00000000..e322cf9c --- /dev/null +++ b/apps/web/src/style/zIndex.ts @@ -0,0 +1,29 @@ +export const Z_INDEX = { + // common + behind: -1, + base: 1, + raised: 2, + elevated: 3, + foreground: 4, + localUnderlay: 9, + localOverlay: 10, + localOverlayRaised: 11, + + // component + appBar: 99, + sheetContent: 999, + navigation: 1000, + sticky: 1001, + contextual: 1002, + notification: 9999, + overlay: 10000, + popover: 10001, + popoverRaised: 10002, + modal: 99999, + tooltip: 100001, + modalRaised: 100002, + toast: 1000000, + bottomSheet: 100000000, + activeSlide: 123123123, + dimmed: 999999999, +} as const; diff --git a/apps/web/src/types/modal.ts b/apps/web/src/types/modal.ts index c294a7c2..6b175bfc 100644 --- a/apps/web/src/types/modal.ts +++ b/apps/web/src/types/modal.ts @@ -1,4 +1,4 @@ -import { ReactNode } from "react"; +import type { CSSProperties, ReactNode } from "react"; export type ModalType = { isOpen: boolean; @@ -40,7 +40,11 @@ export type FunnelModalType = { onClose?: () => void; onConfirm?: () => void; onPrevious?: () => void; - overlayIndex?: number; // 오버레이 z-index 조절용 + options?: { + quitButton?: boolean; + previousButton?: boolean; + }; + overlayIndex?: CSSProperties["zIndex"]; // 오버레이 z-index 조절용 }; export type ActionModalType = { diff --git a/lerna.json b/lerna.json index 2237690a..6fea781d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,9 @@ { "npmClient": "pnpm", - "packages": [".", "packages/*", "apps/*"], - "version": "2.0.12" -} + "packages": [ + ".", + "packages/*", + "apps/*" + ], + "version": "2.0.13" +} \ No newline at end of file diff --git a/package.json b/package.json index a979a8bb..8530338f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "layer", - "version": "2.0.12", + "version": "2.0.13", "private": true, "scripts": { "web": "pnpm -F @layer/web", diff --git a/packages/shared/package.json b/packages/shared/package.json index daaf3bb1..888365ab 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "name": "@layer/shared", - "version": "2.0.12", + "version": "2.0.13", "description": "", "main": "index.ts", "types": "./index.ts",