diff --git a/src/Detail/api/getBookDetail.ts b/src/Detail/api/getBookDetail.ts index ede46f10..c8447bad 100644 --- a/src/Detail/api/getBookDetail.ts +++ b/src/Detail/api/getBookDetail.ts @@ -1,14 +1,11 @@ import { api } from '../../libs/api'; -export async function getBookDetail() { - const data = await api.get( - `/api/books/detail/ee4f66f9-9cf4-4b28-90f4-f71d0ecba021`, - { - headers: { - 'Content-Type': 'application/json', - }, +export async function getBookDetail(bookUuid: string) { + const data = await api.get(`/api/books/detail/${bookUuid}`, { + headers: { + 'Content-Type': 'application/json', }, - ); + }); return data.data.data; } diff --git a/src/Detail/components/LecueNoteListContainer/AlretBanner/AlertBanner.style.ts b/src/Detail/components/LecueNoteListContainer/AlretBanner/AlertBanner.style.ts new file mode 100644 index 00000000..b39cff89 --- /dev/null +++ b/src/Detail/components/LecueNoteListContainer/AlretBanner/AlertBanner.style.ts @@ -0,0 +1,28 @@ +import styled from '@emotion/styled'; + +export const ButtonWrapper = styled.div` + display: flex; + align-items: center; + flex-direction: column; + position: fixed; + bottom: 2rem; + + width: 92%; +`; + +export const AlertBanner = styled.div` + display: flex; + gap: 0.4rem; + justify-content: center; + + width: 90%; + padding: 1.1rem 2.35rem; + margin-bottom: 1rem; + + border-radius: 0.6rem; + background: ${({ theme }) => theme.colors.white}; + color: ${({ theme }) => theme.colors.key}; + + text-align: center; + ${({ theme }) => theme.fonts.Caption2_SB_12}; +`; diff --git a/src/Detail/components/LecueNoteListContainer/AlretBanner/index.tsx b/src/Detail/components/LecueNoteListContainer/AlretBanner/index.tsx new file mode 100644 index 00000000..1b82f12f --- /dev/null +++ b/src/Detail/components/LecueNoteListContainer/AlretBanner/index.tsx @@ -0,0 +1,23 @@ +import { IcCaution } from '../../../../assets'; +import Button from '../../../../components/common/Button'; +import * as S from './AlertBanner.style'; + +interface AlertBannerProps { + onClick: () => void; +} + +function AlertBanner({ onClick }: AlertBannerProps) { + return ( + + + + 스티커는 한 번 붙이면 수정/삭제할 수 없습니다 + + + + ); +} + +export default AlertBanner; diff --git a/src/Detail/components/LecueNoteListContainer/LecueNoteListContainer.style.ts b/src/Detail/components/LecueNoteListContainer/LecueNoteListContainer.style.ts index 7beffc27..0b932675 100644 --- a/src/Detail/components/LecueNoteListContainer/LecueNoteListContainer.style.ts +++ b/src/Detail/components/LecueNoteListContainer/LecueNoteListContainer.style.ts @@ -40,30 +40,3 @@ export const WriteButton = styled.button` width: 6.8rem; height: 6.8rem; `; - -export const ButtonWrapper = styled.div` - display: flex; - align-items: center; - flex-direction: column; - position: fixed; - bottom: 2rem; - - width: 92%; -`; - -export const AlertBanner = styled.div` - display: flex; - gap: 0.4rem; - justify-content: center; - - width: 90%; - padding: 1.1rem 2.35rem; - margin-bottom: 1rem; - - border-radius: 0.6rem; - background: ${({ theme }) => theme.colors.white}; - color: ${({ theme }) => theme.colors.key}; - - text-align: center; - ${({ theme }) => theme.fonts.Caption2_SB_12}; -`; diff --git a/src/Detail/components/LecueNoteListContainer/index.tsx b/src/Detail/components/LecueNoteListContainer/index.tsx index 56c28a7d..a6a63b19 100644 --- a/src/Detail/components/LecueNoteListContainer/index.tsx +++ b/src/Detail/components/LecueNoteListContainer/index.tsx @@ -7,15 +7,14 @@ import { BtnFloatingStickerOrange, BtnFloatingWrite, BtnFloatingWriteOrange, - IcCaution, } from '../../../assets'; -import Button from '../../../components/common/Button'; import usePostStickerState from '../../../StickerAttach/hooks/usePostStickerState'; import { NoteType, postedStickerType } from '../../type/lecueBookType'; import EmptyView from '../EmptyView'; import LecueNoteListHeader from '../LecueNoteLIstHeader'; import LinearView from '../LinearView'; import ZigZagView from '../ZigZagView'; +import AlertBanner from './AlretBanner'; import * as S from './LecueNoteListContainer.style'; interface LecueNoteListContainerProps { @@ -25,25 +24,34 @@ interface LecueNoteListContainerProps { postedStickerList: postedStickerType[]; isEditable: boolean; setEditableStateFalse: () => void; + bookUuid: string; + bookId: number; } -function LecueNoteListContainer({ - noteNum, - backgroundColor, - noteList, - postedStickerList, - isEditable, - setEditableStateFalse, -}: LecueNoteListContainerProps) { +function LecueNoteListContainer(props: LecueNoteListContainerProps) { + const { + noteNum, + backgroundColor, + noteList, + postedStickerList, + isEditable, + setEditableStateFalse, + bookUuid, + bookId, + } = props; //hooks const location = useLocation(); const navigate = useNavigate(); - const scrollRef = useRef(document.createElement('div')); + const scrollRef = useRef(null); + //storage const storedValue = sessionStorage.getItem('scrollPosition'); const savedScrollPosition = storedValue !== null ? parseInt(storedValue, 10) : 0; + //state + const [fullHeight, setFullHeight] = useState(null); + const [heightFromBottom, setHeightFromBottom] = useState(null); const [isZigZagView, setIsZigZagView] = useState(true); const [stickerState, setStickerState] = useState({ postedStickerId: 0, @@ -51,27 +59,8 @@ function LecueNoteListContainer({ positionX: 0, positionY: savedScrollPosition, }); - const { state } = location; - const postMutation = usePostStickerState(); - - useEffect(() => { - // state : 라우터 타고 온 스티커 값, 즉 스티커 값을 갖고 있는 상태라면 - if (state) { - window.scrollTo(0, savedScrollPosition); - const { stickerId, stickerImage } = state.sticker; - setStickerState((prev) => ({ - ...prev, - postedStickerId: stickerId, - stickerImage: stickerImage, - })); - } else { - // editable 상태 변경 - setEditableStateFalse(); - } - }, [state, isEditable]); - // 스티커 위치 값 저장 const handleDrag = (_e: DraggableEvent, ui: DraggableData) => { const { positionX, positionY } = stickerState; @@ -82,9 +71,7 @@ function LecueNoteListContainer({ })); }; - // 스티커 버튼 클릭시 const handleClickStickerButton = () => { - // 현재 스크롤 위치 저장 sessionStorage.setItem('scrollPosition', window.scrollY.toString()); navigate('/sticker-pack'); @@ -94,17 +81,48 @@ function LecueNoteListContainer({ navigate('/create-note'); }; + useEffect(() => { + if (scrollRef.current) { + if (scrollRef.current.offsetHeight) { + setFullHeight(scrollRef.current.offsetHeight); + } + + if (fullHeight !== null) { + setHeightFromBottom(fullHeight - stickerState.positionY); + } + } + }, [fullHeight, stickerState.positionY]); + + useEffect(() => { + // state : 라우터 타고 온 스티커 값 + if (state) { + window.scrollTo(0, savedScrollPosition); + const { stickerId, stickerImage } = state.sticker; + setStickerState((prev) => ({ + ...prev, + postedStickerId: stickerId, + stickerImage: stickerImage, + })); + } else { + // editable 상태 변경 + setEditableStateFalse(); + } + }, [state, isEditable]); + + const postMutation = usePostStickerState(bookUuid); + const handleClickDone = () => { // 다 붙였을 때 post 실행 - const { postedStickerId, positionX, positionY } = stickerState; - const bookId = 1; - - postMutation.mutate({ - postedStickerId: postedStickerId, - bookId: bookId, - positionX: positionX, - positionY: positionY, - }); + const { postedStickerId, positionX } = stickerState; + + if (heightFromBottom !== null) { + postMutation.mutate({ + postedStickerId: postedStickerId, + bookId: bookId, + positionX: positionX, + positionY: heightFromBottom, + }); + } setEditableStateFalse(); }; @@ -125,6 +143,7 @@ function LecueNoteListContainer({ ) : isZigZagView ? ( )} - {isEditable && ( - <> - - - - 스티커는 한 번 붙이면 수정/삭제할 수 없습니다 - - - - - )} + {isEditable && } ); } diff --git a/src/Detail/components/LecueNoteModal/LecueNoteModal.style.ts b/src/Detail/components/LecueNoteModal/LecueNoteModal.style.ts index dbb43777..2bbefcd0 100644 --- a/src/Detail/components/LecueNoteModal/LecueNoteModal.style.ts +++ b/src/Detail/components/LecueNoteModal/LecueNoteModal.style.ts @@ -6,8 +6,7 @@ export const BlurryContainer = styled.div` align-items: center; position: fixed; top: 0; - left: 0; - z-index: 9999; + z-index: 10; width: 100vw; height: 100vh; @@ -27,7 +26,7 @@ export const LecueNoteModalWrapper = styled.div<{ border-radius: 0.4rem; ${({ noteBackground }) => { - if (noteBackground.substring(0, 1) === '#') { + if (noteBackground?.substring(0, 1) === '#') { return `background-color: ${noteBackground}`; } else { return `background: url(${noteBackground})`; diff --git a/src/Detail/components/ZigZagView/ZigZagView.style.ts b/src/Detail/components/ZigZagView/ZigZagView.style.ts index 04cbf8fe..e985e03d 100644 --- a/src/Detail/components/ZigZagView/ZigZagView.style.ts +++ b/src/Detail/components/ZigZagView/ZigZagView.style.ts @@ -14,16 +14,6 @@ export const LecueNoteContainer = styled.div` height: 20.6rem; `; -export const StickerContainer = styled.div` - position: absolute; - - width: 34.2rem; - height: 100%; - padding: 0.4rem 0 2rem; - - background: none; -`; - export const Sticker = styled.div<{ stickerImage: string; isEditable?: boolean; diff --git a/src/Detail/components/ZigZagView/index.tsx b/src/Detail/components/ZigZagView/index.tsx index 71aa2527..6a28b887 100644 --- a/src/Detail/components/ZigZagView/index.tsx +++ b/src/Detail/components/ZigZagView/index.tsx @@ -12,6 +12,7 @@ interface ZigZagViewProps { isEditable: boolean; postedStickerList: postedStickerType[]; savedScrollPosition: number; + fullHeight: number | null; } const ZigZagView = forwardRef(function ZigZagView( @@ -22,6 +23,7 @@ const ZigZagView = forwardRef(function ZigZagView( isEditable, postedStickerList, savedScrollPosition, + fullHeight, }: ZigZagViewProps, ref: React.Ref, ) { @@ -34,7 +36,6 @@ const ZigZagView = forwardRef(function ZigZagView( ))} - {/* */} {isEditable && ( )} - {postedStickerList.map((data) => ( - false} - nodeRef={nodeRef} - key={data.postedStickerId} - defaultPosition={{ x: data.positionX, y: data.positionY }} - > - - - ))} - {/* */} + {postedStickerList.map( + (data) => + fullHeight !== null && ( + false} + nodeRef={nodeRef} + key={data.postedStickerId} + defaultPosition={{ + x: data.positionX, + y: fullHeight - data.positionY, + }} + > + + + ), + )} ); }); diff --git a/src/Detail/hooks/useGetBookDetail.ts b/src/Detail/hooks/useGetBookDetail.ts index c4d6158f..74ed1454 100644 --- a/src/Detail/hooks/useGetBookDetail.ts +++ b/src/Detail/hooks/useGetBookDetail.ts @@ -2,10 +2,10 @@ import { useQuery } from 'react-query'; import { getBookDetail } from '../api/getBookDetail'; -export default function useGetBookDetail() { +export default function useGetBookDetail(bookUuid: string) { const { data: bookDetail } = useQuery( - ['useGetBookDetail'], - () => getBookDetail(), + ['useGetBookDetail', bookUuid], + () => getBookDetail(bookUuid), { onError: () => { console.error; diff --git a/src/Detail/page/DetailPage/index.tsx b/src/Detail/page/DetailPage/index.tsx index 7e4c32ab..d971c377 100644 --- a/src/Detail/page/DetailPage/index.tsx +++ b/src/Detail/page/DetailPage/index.tsx @@ -1,4 +1,5 @@ import { useState } from 'react'; +import { useParams } from 'react-router-dom'; import Header from '../../../components/common/Header'; import BookInfoBox from '../../components/BookInfoBox'; @@ -8,9 +9,11 @@ import useGetBookDetail from '../../hooks/useGetBookDetail'; import * as S from './DetailPage.style'; function DetailPage() { - const { bookDetail } = useGetBookDetail(); const [isEditable, setIsEditable] = useState(true); + const { bookUuid } = useParams() as { bookUuid: string }; + const { bookDetail } = useGetBookDetail(bookUuid); + const setEditableStateFalse = () => { setIsEditable(false); }; @@ -23,6 +26,8 @@ function DetailPage() { } /> } /> } /> - } /> + } /> } /> } /> } /> - } /> + } /> } /> } /> } /> diff --git a/src/StickerAttach/api/postStickerState.ts b/src/StickerAttach/api/postStickerState.ts index 471d4ee9..8423eac5 100644 --- a/src/StickerAttach/api/postStickerState.ts +++ b/src/StickerAttach/api/postStickerState.ts @@ -7,8 +7,6 @@ export async function postStickerState({ positionX, positionY, }: postedStickerParams) { - console.log('api', postedStickerId, bookId, positionX, positionY); - const data = await api.post( '/api/stickers', { diff --git a/src/StickerAttach/hooks/usePostStickerState.ts b/src/StickerAttach/hooks/usePostStickerState.ts index 2ef10f63..0e69e570 100644 --- a/src/StickerAttach/hooks/usePostStickerState.ts +++ b/src/StickerAttach/hooks/usePostStickerState.ts @@ -5,7 +5,7 @@ import { useNavigate } from 'react-router-dom'; import { postStickerState } from '../api/postStickerState'; import { postedStickerParams } from '../type/postStickerType'; -const usePostStickerState = () => { +const usePostStickerState = (bookUuId: string) => { const navigate = useNavigate(); const mutation = useMutation({ mutationFn: ({ @@ -22,7 +22,7 @@ const usePostStickerState = () => { }); }, onSuccess: () => { - navigate('/lecue-book'); + navigate(`/lecue-book/${bookUuId}`); }, onError: (err: AxiosError) => console.log(err), diff --git a/src/StickerPack/api/getBookUuid.ts b/src/StickerPack/api/getBookUuid.ts new file mode 100644 index 00000000..5d16c07f --- /dev/null +++ b/src/StickerPack/api/getBookUuid.ts @@ -0,0 +1,12 @@ +import { api } from '../../libs/api'; + +export async function getBookUuid(bookId: number) { + const data = await api.get(`/api/stickers/${bookId}`, { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${import.meta.env.VITE_APP_TOKEN}`, + }, + }); + + return data.data.data.bookUuid; +} diff --git a/src/StickerPack/api/getStickerPack.ts b/src/StickerPack/api/getStickerPack.ts index 8f451d0f..2998840d 100644 --- a/src/StickerPack/api/getStickerPack.ts +++ b/src/StickerPack/api/getStickerPack.ts @@ -8,5 +8,5 @@ export async function getStickerPack(bookId: number) { }, }); - return data.data.data; + return data.data.data.stickerPackList; } diff --git a/src/StickerPack/components/StickerList/index.tsx b/src/StickerPack/components/StickerList/index.tsx index af4c779f..feec404c 100644 --- a/src/StickerPack/components/StickerList/index.tsx +++ b/src/StickerPack/components/StickerList/index.tsx @@ -20,7 +20,7 @@ function StickerList(props: StickerListProps) { {data.stickerCategory} - {data.stickerList.map((sticker) => ( + {data?.stickerList?.map((sticker) => ( getBookUuid(bookId), + { + onError: () => { + console.error; + }, + }, + ); + + return { bookUuId }; +} diff --git a/src/StickerPack/page/StickerPack/index.tsx b/src/StickerPack/page/StickerPack/index.tsx index 75c0dc83..15c6fe3b 100644 --- a/src/StickerPack/page/StickerPack/index.tsx +++ b/src/StickerPack/page/StickerPack/index.tsx @@ -6,6 +6,7 @@ import Button from '../../../components/common/Button/index.tsx'; import Header from '../../../components/common/Header/index.tsx'; import CommonModal from '../../../components/common/Modal/CommonModal.tsx'; import StickerList from '../../components/StickerList/index.tsx'; +import useGetBookUuid from '../../hooks/useGetBookUuid.ts'; // type import { stickerType } from '../../type/stickerPackType.ts'; // style @@ -34,8 +35,10 @@ function StickerPack() { })); }; + const { bookUuId } = useGetBookUuid(1); + const handleClickDone = () => { - navigate('/sticker-attach', { + navigate(`/sticker-attach/${bookUuId}`, { state: { sticker: selectedStickerData }, }); };