From fe2013307c84dc35173fdf59ad17f57dad07cbd2 Mon Sep 17 00:00:00 2001 From: yyypearl Date: Wed, 5 Feb 2025 23:54:21 +0900 Subject: [PATCH 1/9] =?UTF-8?q?=E2=9C=A8=20feat(#141):=20=ED=99=88=20?= =?UTF-8?q?=ED=97=A4=EB=93=9C=ED=83=80=EC=9D=B4=ED=8B=80=20=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=ED=8C=85=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=ED=8E=B8?= =?UTF-8?q?=EC=A7=80=20=EC=B4=9D=20=EA=B0=9C=EC=88=98=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EC=83=81=ED=83=9C=EA=B4=80=EB=A6=AC=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/planet/page.tsx | 31 +++++--------------- src/components/planet/PlanetSlide.tsx | 42 +++++++++++++-------------- 2 files changed, 28 insertions(+), 45 deletions(-) diff --git a/src/app/planet/page.tsx b/src/app/planet/page.tsx index d33234f5..7bcb29ae 100644 --- a/src/app/planet/page.tsx +++ b/src/app/planet/page.tsx @@ -56,7 +56,7 @@ const PlanetPage = () => { const [spaceInfo, setSpaceInfo] = useState(null); const [user, setUser] = useRecoilState(userState); - const [countLetter, setCountLetter] = useState(0); + // const [countLetter, setCountLetter] = useState(0); const accessToken = getAccessToken(); // 에러핸들링 const [showTooltip, setShowTooltip] = useState(false); @@ -91,7 +91,7 @@ const PlanetPage = () => { try { const response = await getLetterCount(); console.log('모든 편지 수 조회 성공:', response.data); - setCountLetter(response.data.letterCount); + // setCountLetter(response.data.letterCount); setCurrentOrbits(response.data.content); if (response.data.letterCount < 3 && getInitUserToast() !== 'true') { @@ -471,21 +471,7 @@ const PlanetPage = () => { /> - - {countLetter < 3 ? ( - <> - {user.name}님의 스페이스를 - <br /> - 편지로 수놓아 보세요 - </> - ) : ( - <> - {user.name}님의 스페이스에 - <br /> - <Em>{countLetter}개의 편지</Em>가 수놓여 있어요! - </> - )} - + {user.name}님의 스페이스 { { router.push('/planet/manage'); }} @@ -523,7 +510,7 @@ const PlanetPage = () => { currentOrbits={currentOrbits || []} setCurrentOrbits={setCurrentOrbits} onEditPlanetName={handleEditPlanetName} - setCountLetter={setCountLetter} + // setCountLetter={setCountLetter} setChange={setChange} /> @@ -618,11 +605,7 @@ const Top = styled.div` const Title = styled.div` color: ${theme.colors.white}; - ${(props) => props.theme.fonts.heading02}; -`; - -const Em = styled.span` - ${(props) => props.theme.fonts.heading01} + ${(props) => props.theme.fonts.heading01}; `; const TagList = styled.div` diff --git a/src/components/planet/PlanetSlide.tsx b/src/components/planet/PlanetSlide.tsx index ba480e82..f389b1a9 100644 --- a/src/components/planet/PlanetSlide.tsx +++ b/src/components/planet/PlanetSlide.tsx @@ -1,9 +1,9 @@ -import React from "react"; -import styled from "styled-components"; -import { motion, AnimatePresence } from "framer-motion"; -import { SpaceInfo } from "@/types/space"; -import Planet from "../common/Planet"; -import { Orbit } from "@/types/orbit"; +import React from 'react'; +import styled from 'styled-components'; +import { motion, AnimatePresence } from 'framer-motion'; +import { SpaceInfo } from '@/types/space'; +import Planet from '../common/Planet'; +import { Orbit } from '@/types/orbit'; interface PlanetSlideProps { idx: number; @@ -12,36 +12,36 @@ interface PlanetSlideProps { direction: number; onEditPlanetName: (newName: string) => void; setCurrentOrbits: React.Dispatch>; - setCountLetter: React.Dispatch>; + // setCountLetter: React.Dispatch>; setChange: React.Dispatch>; } const slideVariants = { hidden: (direction: number) => ({ - x: direction > 0 ? "100%" : "-100%", - opacity: 0, + x: direction > 0 ? '100%' : '-100%', + opacity: 0 }), visible: { x: 0, opacity: 1, transition: { - type: "spring", + type: 'spring', stiffness: 300, damping: 25, // Adjusted for a smoother feel - mass: 0.5, // Added mass for more natural movement - }, + mass: 0.5 // Added mass for more natural movement + } }, exit: (direction: number) => ({ - x: direction > 0 ? "-100%" : "100%", + x: direction > 0 ? '-100%' : '100%', opacity: 0, transition: { - type: "spring", + type: 'spring', stiffness: 300, damping: 25, // Consistent with the enter transition mass: 0.5, - ease: [0.4, 0.0, 0.2, 1], // Ease-in-out effect - }, - }), + ease: [0.4, 0.0, 0.2, 1] // Ease-in-out effect + } + }) }; const PlanetSlide = ({ @@ -50,9 +50,9 @@ const PlanetSlide = ({ spaceInfo, currentOrbits, setCurrentOrbits, - setCountLetter, + // setCountLetter, setChange, - onEditPlanetName, + onEditPlanetName }: PlanetSlideProps) => { return ( @@ -67,11 +67,11 @@ const PlanetSlide = ({ > {/* */} From c6920c3daf85db2bf7aa9d71af9aab5902da86b4 Mon Sep 17 00:00:00 2001 From: yyypearl Date: Wed, 5 Feb 2025 23:54:33 +0900 Subject: [PATCH 2/9] =?UTF-8?q?=E2=9C=A8=20feat(#141):=20=ED=8E=B8?= =?UTF-8?q?=EC=A7=80=20=ED=99=80=EB=93=9C=20=EB=8F=99=EC=9E=91=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/Planet.tsx | 66 ++++++++++++++++---------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/components/common/Planet.tsx b/src/components/common/Planet.tsx index c9e90754..5343876e 100644 --- a/src/components/common/Planet.tsx +++ b/src/components/common/Planet.tsx @@ -1,17 +1,17 @@ -import React, { useState } from "react"; -import Image from "next/image"; -import styled from "styled-components"; -import Tag from "./Tag"; -import Button from "./Button"; -import { useRouter } from "next/navigation"; -import ConfirmModal from "./ConfirmModal"; -import { useRecoilState, useSetRecoilState } from "recoil"; -import { toastState } from "@/recoil/toastStore"; -import { deletePlanetLetter } from "@/api/planet/letter/spaceLetter"; -import { droppedLetterState } from "@/recoil/letterStore"; -import BlinkTag from "./BlinkingTag"; -import { useToast } from "@/hooks/useToast"; -import { getCookie } from "@/utils/storage"; +import React, { useState } from 'react'; +import Image from 'next/image'; +import styled from 'styled-components'; +import Tag from './Tag'; +import Button from './Button'; +import { useRouter } from 'next/navigation'; +import ConfirmModal from './ConfirmModal'; +import { useRecoilState, useSetRecoilState } from 'recoil'; +import { toastState } from '@/recoil/toastStore'; +import { deletePlanetLetter } from '@/api/planet/letter/spaceLetter'; +import { droppedLetterState } from '@/recoil/letterStore'; +import BlinkTag from './BlinkingTag'; +import { useToast } from '@/hooks/useToast'; +import { getCookie } from '@/utils/storage'; interface Orbit { letterId: string; @@ -27,7 +27,7 @@ interface PlanetProps { orbits?: Orbit[]; onEditPlanetName: (newName: string) => void; setCurrentOrbits: React.Dispatch>; - setCountLetter: React.Dispatch>; + // setCountLetter: React.Dispatch>; setChange?: React.Dispatch>; } @@ -38,17 +38,17 @@ const Planet = (props: PlanetProps) => { orbits, onEditPlanetName, setCurrentOrbits, - setCountLetter, - setChange, + // setCountLetter, + setChange } = props; const router = useRouter(); const { showToast } = useToast(); const [hold, setHold] = useState(false); const [confirmDeleteModal, setConfirmDeleteModal] = useState(false); - const [orbitId, setOrbitId] = useState(""); - const [senderName, setSenderName] = useState(""); - const type = getCookie("letter-tagtype"); // 편지 태그 - 이름(1) / 이름과날짜(2) 구분용 + const [orbitId, setOrbitId] = useState(''); + const [senderName, setSenderName] = useState(''); + const type = getCookie('letter-tagtype'); // 편지 태그 - 이름(1) / 이름과날짜(2) 구분용 const radius = 150; // Orbit들이 배치될 원의 반지름 const center = 150; // 행성이 위치할 중앙의 좌표 @@ -65,12 +65,13 @@ const Planet = (props: PlanetProps) => { return orbit ? orbit.senderName : undefined; }; - const handleShowHold = (orbitId: string) => { - const senderName = findSenderName(orbitId, orbits); - setOrbitId(orbitId); - setSenderName(senderName ?? ""); - setHold(!hold); - }; + // 편지 홀드 (이동하기, 삭제하기 버튼) 기능 주석 + // const handleShowHold = (orbitId: string) => { + // const senderName = findSenderName(orbitId, orbits); + // setOrbitId(orbitId); + // setSenderName(senderName ?? ''); + // setHold(!hold); + // }; const handleOverlayClick = (e: React.MouseEvent) => { setHold(false); @@ -92,14 +93,14 @@ const Planet = (props: PlanetProps) => { try { await deletePlanetLetter(orbitId); setConfirmDeleteModal(false); - console.log("편지 삭제 성공"); + console.log('편지 삭제 성공'); setCurrentOrbits((prevOrbits) => prevOrbits?.filter((orbit) => orbit.letterId !== orbitId) ); - setCountLetter((prevCount) => (prevCount ? prevCount - 1 : prevCount)); + // setCountLetter((prevCount) => (prevCount ? prevCount - 1 : prevCount)); } catch { - console.log("편지 삭제 실패"); + console.log('편지 삭제 실패'); } // 토스트 메세지 @@ -107,7 +108,7 @@ const Planet = (props: PlanetProps) => { showToast(`${orbit?.senderName} 님의 편지가 삭제되었어요`, { icon: true, close: false, - bottom: "230px", + bottom: '230px' }); if (setChange) { setChange((prev) => !prev); @@ -133,7 +134,6 @@ const Planet = (props: PlanetProps) => { priority onContextMenu={handleContextMenu} /> - {/* */} {orbits && orbits.map((orbit, index) => { const angle = -(index / orbits.length) * 2 * Math.PI - Math.PI / 2; // 각 Orbit 요소의 각도 계산 @@ -145,7 +145,7 @@ const Planet = (props: PlanetProps) => { key={orbit.letterId} style={{ transform: `translate(${x}px, ${y}px)`, - transition: "transform 0.8s ease", + transition: 'transform 0.8s ease' }} > {orbit.letterId === droppedLetter.tagId ? ( @@ -164,7 +164,7 @@ const Planet = (props: PlanetProps) => { handleTagClick(orbit.letterId); }} onHold={() => { - handleShowHold(orbit.letterId); + // handleShowHold(orbit.letterId); }} /> ) From 93ddd1a41bbb49c14063e264974c92b4977c2102 Mon Sep 17 00:00:00 2001 From: yyypearl Date: Wed, 5 Feb 2025 23:55:01 +0900 Subject: [PATCH 3/9] =?UTF-8?q?=F0=9F=92=84=20design(#141):=20=ED=96=89?= =?UTF-8?q?=EC=84=B1=20=EA=B4=80=EB=A6=AC=20hamburger=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20UI=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assets/icons/ic_hamburger_menu_white.svg | 5 + src/components/common/Tag.tsx | 143 ++++++++++-------- 2 files changed, 84 insertions(+), 64 deletions(-) create mode 100644 public/assets/icons/ic_hamburger_menu_white.svg diff --git a/public/assets/icons/ic_hamburger_menu_white.svg b/public/assets/icons/ic_hamburger_menu_white.svg new file mode 100644 index 00000000..3adfaada --- /dev/null +++ b/public/assets/icons/ic_hamburger_menu_white.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/common/Tag.tsx b/src/components/common/Tag.tsx index 84dff616..230a634c 100644 --- a/src/components/common/Tag.tsx +++ b/src/components/common/Tag.tsx @@ -1,14 +1,14 @@ -import { deleteOrbitLetter } from "@/api/planet/letter/spaceLetter"; -import { planetRefState } from "@/recoil/RefStore"; -import { theme } from "@/styles/theme"; -import { Orbit } from "@/types/orbit"; -import Image from "next/image"; -import React, { useRef, useState } from "react"; -import { useRecoilState } from "recoil"; -import styled, { css } from "styled-components"; - -type tagType = "orbit" | "planet" | "letter"; -type iconType = "chevron" | "edit" | "plus"; +import { deleteOrbitLetter } from '@/api/planet/letter/spaceLetter'; +import { planetRefState } from '@/recoil/RefStore'; +import { theme } from '@/styles/theme'; +import { Orbit } from '@/types/orbit'; +import Image from 'next/image'; +import React, { useRef, useState } from 'react'; +import { useRecoilState } from 'recoil'; +import styled, { css } from 'styled-components'; + +type tagType = 'orbit' | 'planet' | 'letter'; +type iconType = 'chevron' | 'edit' | 'plus' | 'hamburger'; interface TagProps { tagType: tagType; @@ -17,6 +17,7 @@ interface TagProps { isNew?: boolean; isDeleteMode?: boolean; icon?: iconType; + iconPosition?: 'right' | 'left'; orbitType?: string; receivedDate?: string; onClick?: () => void; @@ -37,6 +38,7 @@ const Tag = (props: TagProps) => { isNew, isDeleteMode = false, icon, + iconPosition = 'right', orbitType, receivedDate, onClick, @@ -46,7 +48,7 @@ const Tag = (props: TagProps) => { onDelete, isDragable = false, onDragEnd, - onTouchEnd, + onTouchEnd } = props; const [isEditing, setIsEditing] = useState(false); @@ -60,7 +62,7 @@ const Tag = (props: TagProps) => { const [planetRef, setPlanetRef] = useRecoilState(planetRefState); const handleEditClick = () => { - if (icon === "edit") { + if (icon === 'edit') { setIsEditing(true); } }; @@ -73,17 +75,17 @@ const Tag = (props: TagProps) => { return `${match[1]}.${match[2]}.${match[3]}`; } - throw new Error("Invalid date format"); + throw new Error('Invalid date format'); }; const handleDragStart = () => { - if (onDragEnd && tagId && name && tagType === "orbit") { - console.log("드래그 시작"); + if (onDragEnd && tagId && name && tagType === 'orbit') { + console.log('드래그 시작'); setIsDragging(true); clearHoldTimeout(); onDragEnd({ letterId: tagId, - senderName: name, + senderName: name }); } }; @@ -105,10 +107,10 @@ const Tag = (props: TagProps) => { if (tagId && onDelete) { try { const response = await deleteOrbitLetter(tagId); - console.log("궤도 편지 삭제 성공", response); + console.log('궤도 편지 삭제 성공', response); onDelete(tagId); } catch { - console.log("궤도 편지 삭제 실패"); + console.log('궤도 편지 삭제 실패'); } } }; @@ -148,24 +150,26 @@ const Tag = (props: TagProps) => { }; const renderIcon = () => { - if (icon === "chevron") { - return "/assets/icons/ic_chevron_right.svg"; - } else if (icon === "edit") { - return "/assets/icons/ic_edit.svg"; - } else if (icon === "plus") { - return "/assets/icons/ic_plus.svg"; + if (icon === 'chevron') { + return '/assets/icons/ic_chevron_right.svg'; + } else if (icon === 'edit') { + return '/assets/icons/ic_edit.svg'; + } else if (icon === 'plus') { + return '/assets/icons/ic_plus.svg'; + } else if (icon === 'hamburger') { + return '/assets/icons/ic_hamburger_menu_white.svg'; } - return ""; + return ''; }; //모바일 터치 드래그 const handleTouchStart = (e: React.TouchEvent) => { - if (tagType === "letter") { + if (tagType === 'letter') { handleHoldStart(); } - if (isDragable && tagType === "orbit") { + if (isDragable && tagType === 'orbit') { e.stopPropagation(); - console.log("터치 시작", e.touches?.[0]); + console.log('터치 시작', e.touches?.[0]); const touch = e.touches?.[0]; if (touch) { @@ -173,18 +177,18 @@ const Tag = (props: TagProps) => { startPositionRef.current = position; } - e.currentTarget.addEventListener("touchmove", handleTouchMove, { - passive: false, + e.currentTarget.addEventListener('touchmove', handleTouchMove, { + passive: false }); - e.currentTarget.addEventListener("touchend", handleTouchEnd, { - once: true, + e.currentTarget.addEventListener('touchend', handleTouchEnd, { + once: true }); } }; const handleTouchMove = (e: TouchEvent) => { const startPosition = startPositionRef.current; - console.log("터치 움직임", startPosition); + console.log('터치 움직임', startPosition); if (startPosition) { const touch = e.touches[0]; @@ -193,14 +197,14 @@ const Tag = (props: TagProps) => { setTranslate({ x: touch.clientX - startPosition.x, - y: touch.clientY - startPosition.y, + y: touch.clientY - startPosition.y }); if (tagRef.current) { - tagRef.current.style.zIndex = "999999"; + tagRef.current.style.zIndex = '999999'; tagRef.current.style.transform = `translate(${deltaX}px, ${deltaY}px)`; - tagRef.current.style.position = "absolute"; - tagRef.current.style.touchAction = "none"; + tagRef.current.style.position = 'absolute'; + tagRef.current.style.touchAction = 'none'; } if (e.cancelable) { @@ -210,13 +214,13 @@ const Tag = (props: TagProps) => { }; const handleTouchEnd = () => { - if (tagType === "letter") { + if (tagType === 'letter') { handleHoldEnd(); } - console.log("터치 끝"); + console.log('터치 끝'); - if (planetRef && tagRef.current && tagType === "orbit") { + if (planetRef && tagRef.current && tagType === 'orbit') { const parentRect = planetRef.getBoundingClientRect(); const tagRect = tagRef.current.getBoundingClientRect(); const isAtLeast80pxAboveBottom = tagRect.bottom <= parentRect.bottom - 80; @@ -236,22 +240,22 @@ const Tag = (props: TagProps) => { name ) { // 태그가 부모 영역 내에 있고, 밑에서 100px 이상 떨어져 있을 때 - console.log("드래그한 태그가 영역 내에 있습니다."); + console.log('드래그한 태그가 영역 내에 있습니다.'); onDragEnd({ letterId: tagId, - senderName: name, + senderName: name }); onTouchEnd({ letterId: tagId, - senderName: name, + senderName: name }); } else if (!isAtLeast80pxAboveBottom) { // 태그가 부모 영역 밑에서 100px 이내에 있을 때 console.log( - "태그가 부모 영역의 밑에서 100px 이내에 있습니다. 이벤트를 취소합니다." + '태그가 부모 영역의 밑에서 100px 이내에 있습니다. 이벤트를 취소합니다.' ); } else { - console.log("드래그한 태그가 영역 내에 없습니다."); + console.log('드래그한 태그가 영역 내에 없습니다.'); } } @@ -260,13 +264,13 @@ const Tag = (props: TagProps) => { const resetTag = () => { if (tagRef.current) { - tagRef.current.style.transform = ""; - tagRef.current.style.zIndex = ""; - tagRef.current.style.position = "relative"; + tagRef.current.style.transform = ''; + tagRef.current.style.zIndex = ''; + tagRef.current.style.position = 'relative'; } - document.removeEventListener("touchmove", handleTouchMove); - document.removeEventListener("touchend", handleTouchEnd); + document.removeEventListener('touchmove', handleTouchMove); + document.removeEventListener('touchend', handleTouchEnd); }; // useEffect(() => { @@ -287,7 +291,8 @@ const Tag = (props: TagProps) => { { @@ -310,7 +315,7 @@ const Tag = (props: TagProps) => { textLength={editedName?.length || 0} // 텍스트 길이 전달 autoFocus /> - ) : orbitType && receivedDate && orbitType === "2" ? ( + ) : orbitType && receivedDate && orbitType === '2' ? ( {name} {formatDate(receivedDate)} @@ -318,8 +323,8 @@ const Tag = (props: TagProps) => { ) : ( {name} )} - {tagType === "orbit" && isNew && !isDeleteMode && } - {tagType === "orbit" && isDeleteMode && ( + {tagType === 'orbit' && isNew && !isDeleteMode && } + {tagType === 'orbit' && isDeleteMode && ( { onClick={handleDeleteOrbit} /> )} - {tagType === "planet" && ( + {tagType === 'planet' && ( )} @@ -348,9 +354,12 @@ const Box = styled.div<{ $hasName?: boolean; $hasEditIcon?: boolean; $orbitType?: string; + $iconPosition?: string; }>` width: auto; display: inline-flex; + flex-direction: ${({ $iconPosition }) => + $iconPosition === 'left' ? 'row-reverse' : 'row'}; justify-content: center; align-items: center; border-radius: 100px; @@ -360,7 +369,7 @@ const Box = styled.div<{ z-index: 10; ${({ $tagType }) => - $tagType === "orbit" && + $tagType === 'orbit' && css` height: 34px; padding: 6px 23px; @@ -371,10 +380,10 @@ const Box = styled.div<{ `} ${({ $tagType, $hasName, $hasEditIcon }) => - $tagType === "planet" && + $tagType === 'planet' && css` height: 37px; - padding: 7.5px 4px 7.5px 16px; + padding: 7.5px 10px; border-radius: 8px; background: ${theme.colors.gray800}; ${(props) => props.theme.fonts.body08}; @@ -396,17 +405,17 @@ const Box = styled.div<{ `} ${({ $tagType, $orbitType }) => - $tagType === "letter" && + $tagType === 'letter' && css` display: block; max-width: 90px; - padding: ${$orbitType === "2" ? "7.5px 15px" : "11px 15px"}; + padding: ${$orbitType === '2' ? '7.5px 15px' : '11px 15px'}; border-radius: 40px; background: ${theme.colors.sub01}; ${(props) => - $orbitType === "2" ? props.theme.fonts.body8 : props.theme.fonts.body6}; + $orbitType === '2' ? props.theme.fonts.body8 : props.theme.fonts.body6}; line-height: 16px; - font-size: ${$orbitType === "2" && "14px"}; + font-size: ${$orbitType === '2' && '14px'}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -472,7 +481,13 @@ const DeleteIcon = styled(Image)` right: -2px; `; -const IconImage = styled(Image)` +const IconImage = styled(Image)<{ $iconPosition: string }>` + ${({ $iconPosition }) => + $iconPosition === 'left' && + css` + margin-right: 6px; + `}; + -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; From 670e35818d1099b7ee62a838ddbbba2329c81f2e Mon Sep 17 00:00:00 2001 From: yyypearl Date: Thu, 6 Feb 2025 00:00:54 +0900 Subject: [PATCH 4/9] =?UTF-8?q?=F0=9F=93=81=20file(#141):=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20hamburger=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=EC=82=AD=EC=A0=9C,=20kebab=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...mburger_menu_white.svg => ic_hamburger.svg} | 0 public/assets/icons/ic_hamburger_menu.svg | 5 ----- public/assets/icons/ic_kebab.svg | 5 +++++ src/components/common/Tag.tsx | 2 +- src/components/planet/PlanetList.tsx | 18 +++++++++--------- 5 files changed, 15 insertions(+), 15 deletions(-) rename public/assets/icons/{ic_hamburger_menu_white.svg => ic_hamburger.svg} (100%) delete mode 100644 public/assets/icons/ic_hamburger_menu.svg create mode 100644 public/assets/icons/ic_kebab.svg diff --git a/public/assets/icons/ic_hamburger_menu_white.svg b/public/assets/icons/ic_hamburger.svg similarity index 100% rename from public/assets/icons/ic_hamburger_menu_white.svg rename to public/assets/icons/ic_hamburger.svg diff --git a/public/assets/icons/ic_hamburger_menu.svg b/public/assets/icons/ic_hamburger_menu.svg deleted file mode 100644 index 766d8ceb..00000000 --- a/public/assets/icons/ic_hamburger_menu.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/public/assets/icons/ic_kebab.svg b/public/assets/icons/ic_kebab.svg new file mode 100644 index 00000000..a4971b75 --- /dev/null +++ b/public/assets/icons/ic_kebab.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/components/common/Tag.tsx b/src/components/common/Tag.tsx index 230a634c..edcc967f 100644 --- a/src/components/common/Tag.tsx +++ b/src/components/common/Tag.tsx @@ -157,7 +157,7 @@ const Tag = (props: TagProps) => { } else if (icon === 'plus') { return '/assets/icons/ic_plus.svg'; } else if (icon === 'hamburger') { - return '/assets/icons/ic_hamburger_menu_white.svg'; + return '/assets/icons/ic_hamburger.svg'; } return ''; }; diff --git a/src/components/planet/PlanetList.tsx b/src/components/planet/PlanetList.tsx index ae7ed60e..038f9f73 100644 --- a/src/components/planet/PlanetList.tsx +++ b/src/components/planet/PlanetList.tsx @@ -1,12 +1,12 @@ -import { theme } from "@/styles/theme"; -import React from "react"; -import styled from "styled-components"; -import Image from "next/image"; -import Check from "../common/Check"; +import { theme } from '@/styles/theme'; +import React from 'react'; +import styled from 'styled-components'; +import Image from 'next/image'; +import Check from '../common/Check'; import { DraggableProvidedDraggableProps, - DraggableProvidedDragHandleProps, -} from "react-beautiful-dnd"; + DraggableProvidedDragHandleProps +} from 'react-beautiful-dnd'; interface PlanetListProps { id: string; @@ -36,7 +36,7 @@ const PlanetList = (props: PlanetListProps) => { innerRef, dragHandleProps, draggableProps, - modify, + modify } = props; return ( @@ -59,7 +59,7 @@ const PlanetList = (props: PlanetListProps) => { {modify && ( list Date: Thu, 6 Feb 2025 01:05:23 +0900 Subject: [PATCH 5/9] =?UTF-8?q?=E2=9A=99=20chore(#142):=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC=20=ED=99=98=EA=B2=BD=EC=97=90=EC=84=9C=20console.log?= =?UTF-8?q?=20=EB=B8=94=EB=9D=BC=EC=9D=B8=EB=93=9C=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .babelrc | 8 ++++++++ package-lock.json | 6 ++++++ package.json | 1 + 3 files changed, 15 insertions(+) create mode 100644 .babelrc diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..9a771d1d --- /dev/null +++ b/.babelrc @@ -0,0 +1,8 @@ +{ + "presets": ["next/babel"], + "env": { + "production": { + "plugins": ["transform-remove-console"] + } + } +} diff --git a/package-lock.json b/package-lock.json index d1660303..f15fed29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@emotion/styled": "^11.13.0", "@next/third-parties": "^14.2.5", "axios": "^1.7.7", + "babel-plugin-transform-remove-console": "^6.9.4", "browser-image-compression": "^2.0.2", "cookie": "^1.0.0", "eslint-config-airbnb": "^19.0.4", @@ -1622,6 +1623,11 @@ "integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==", "license": "MIT" }, + "node_modules/babel-plugin-transform-remove-console": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", + "integrity": "sha512-88blrUrMX3SPiGkT1GnvVY8E/7A+k6oj3MNvUtTIxJflFzXTw1bHkuJ/y039ouhFMp2prRn5cQGzokViYi1dsg==" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", diff --git a/package.json b/package.json index 7a18413c..821f0960 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@emotion/styled": "^11.13.0", "@next/third-parties": "^14.2.5", "axios": "^1.7.7", + "babel-plugin-transform-remove-console": "^6.9.4", "browser-image-compression": "^2.0.2", "cookie": "^1.0.0", "eslint-config-airbnb": "^19.0.4", From 8ed360b7a7b937ea22bcc329f235f8dbeb39ec8e Mon Sep 17 00:00:00 2001 From: yyypearl Date: Thu, 6 Feb 2025 01:05:56 +0900 Subject: [PATCH 6/9] =?UTF-8?q?=F0=9F=93=81=20file(#141):=20=ED=99=88=20>?= =?UTF-8?q?=20=ED=96=89=EC=84=B1=20=EA=B4=80=EB=A6=AC=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/assets/icons/ic_hamburger_gray.svg | 5 +++++ public/assets/icons/ic_pin.svg | 10 ++++++++++ public/assets/icons/ic_trash.svg | 14 ++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 public/assets/icons/ic_hamburger_gray.svg create mode 100644 public/assets/icons/ic_pin.svg create mode 100644 public/assets/icons/ic_trash.svg diff --git a/public/assets/icons/ic_hamburger_gray.svg b/public/assets/icons/ic_hamburger_gray.svg new file mode 100644 index 00000000..766d8ceb --- /dev/null +++ b/public/assets/icons/ic_hamburger_gray.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/assets/icons/ic_pin.svg b/public/assets/icons/ic_pin.svg new file mode 100644 index 00000000..5d69d159 --- /dev/null +++ b/public/assets/icons/ic_pin.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/assets/icons/ic_trash.svg b/public/assets/icons/ic_trash.svg new file mode 100644 index 00000000..b7f9f723 --- /dev/null +++ b/public/assets/icons/ic_trash.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + From 7951d3e239dd334ddddefc382b71f3bb522d4915 Mon Sep 17 00:00:00 2001 From: yyypearl Date: Thu, 6 Feb 2025 18:34:56 +0900 Subject: [PATCH 7/9] =?UTF-8?q?=E2=9C=A8=20feat(#141):=20=ED=96=89?= =?UTF-8?q?=EC=84=B1=20=EA=B4=80=EB=A6=AC=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EA=B8=B0=EC=A1=B4=20=EC=82=AD=EC=A0=9C=20=EB=AA=A8=EB=93=9C?= =?UTF-8?q?=EB=A5=BC=20=EC=88=9C=EC=84=9C=20=ED=8E=B8=EC=A7=91=20=EB=AA=A8?= =?UTF-8?q?=EB=93=9C=EB=A1=9C=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/planet/manage/page.tsx | 257 ++++++++++++++------------ src/components/common/BottomSheet.tsx | 56 +++--- src/components/planet/PlanetList.tsx | 51 ++--- src/types/planet.ts | 2 +- 4 files changed, 201 insertions(+), 165 deletions(-) diff --git a/src/app/planet/manage/page.tsx b/src/app/planet/manage/page.tsx index a0554be3..daeaab50 100644 --- a/src/app/planet/manage/page.tsx +++ b/src/app/planet/manage/page.tsx @@ -1,37 +1,41 @@ -"use client"; - -import React, { useEffect, useState } from "react"; -import styled, { css } from "styled-components"; -import { theme } from "@/styles/theme"; -import NavigatorBar from "@/components/common/NavigatorBar"; -import Button from "@/components/common/Button"; -import PlanetList from "@/components/planet/PlanetList"; -import Image from "next/image"; -import ConfirmModal from "@/components/common/ConfirmModal"; -import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; +'use client'; + +import React, { useEffect, useState } from 'react'; +import styled, { css } from 'styled-components'; +import { theme } from '@/styles/theme'; +import NavigatorBar from '@/components/common/NavigatorBar'; +import PlanetList from '@/components/planet/PlanetList'; +import Image from 'next/image'; +import ConfirmModal from '@/components/common/ConfirmModal'; +import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'; import { deleteSpaces, getSpaceList, - putSpacesOrder, -} from "@/api/planet/space/space"; -import { useToast } from "@/hooks/useToast"; -import { spaceState } from "@/recoil/spaceStore"; -import { useSetRecoilState } from "recoil"; -import { useRouter } from "next/navigation"; -import Loader, { LoaderContainer } from "@/components/common/Loader"; -import { Planet } from "@/types/planet"; + putSpacesOrder +} from '@/api/planet/space/space'; +import { useToast } from '@/hooks/useToast'; +import { spaceState } from '@/recoil/spaceStore'; +import { useSetRecoilState } from 'recoil'; +import { useRouter } from 'next/navigation'; +import Loader, { LoaderContainer } from '@/components/common/Loader'; +import { Planet } from '@/types/planet'; +import BottomSheet from '@/components/common/BottomSheet'; const PlanetManagePage = () => { const router = useRouter(); const { showToast } = useToast(); const [count, setCount] = useState(null); - const [deleteMode, setDeleteMode] = useState(false); - const [checkedPlanets, setCheckedPlanets] = useState([]); + const [dragMode, setDragMode] = useState(false); + const [selectedId, setSelectedId] = useState(); const [confirmDeleteModal, setConfirmDeleteModal] = useState(false); - const [changedOrder, setChangedOrder] = useState([]); + const [changedOrder, setChangedOrder] = useState< + { spaceId: string; index: number }[] + >([]); const [isLoading, setIsLoading] = useState(false); const [planets, setPlanets] = useState(); + const [showBottom, setShowBottom] = useState(false); + const [isBottomUp, setIsBottomUp] = useState(false); const setViewSpaceId = useSetRecoilState(spaceState); @@ -39,11 +43,11 @@ const PlanetManagePage = () => { try { setIsLoading(true); const response = await getSpaceList(); - console.log("전체 스페이스 목록 조회 성공:", response.data); + console.log('전체 스페이스 목록 조회 성공:', response.data); setPlanets(response.data.spaces); setCount(response.data.spaces.length); } catch (error) { - console.error("전체 스페이스 목록 조회 실패:", error); + console.error('전체 스페이스 목록 조회 실패:', error); } finally { setIsLoading(false); } @@ -53,70 +57,86 @@ const PlanetManagePage = () => { fetchSpaceList(); }, []); - const handleClickDeleteMode = () => { - setDeleteMode(!deleteMode); + const handleClickDragMode = () => { + setDragMode(!dragMode); }; - const handleClickCheckAll = () => { - if (planets && planets.length > 0) { - if (checkedPlanets.length === planets.length) { - setCheckedPlanets([]); - } else { - setCheckedPlanets(planets.map((planet) => planet.spaceId)); - } + const handleOrderEditComplete = async () => { + /* 스페이스 순서 변경 API 호출 */ + try { + const response = await putSpacesOrder({ orders: changedOrder }); + console.log('결과', changedOrder); + console.log('스페이스 순서 변경 성공:', response); + } catch (error) { + console.error('스페이스 순서 변경 실패:', error); } + setDragMode(false); }; const handleChangeChecked = (id: string) => { - if (deleteMode) { - if (checkedPlanets.includes(id)) { - setCheckedPlanets(checkedPlanets.filter((planetId) => planetId !== id)); - } else { - setCheckedPlanets([...checkedPlanets, id]); - } - } else { + if (!dragMode) { /* 선택 행성 조회 모드 */ if (id) { setViewSpaceId(id); - router.push("/planet"); + router.push('/planet'); } } }; + /* BottomSheet 관련 함수 */ + const handleShowBottom = (id: string) => { + setSelectedId(id); + setShowBottom(true); + }; + + const handleBottomUpChange = (state: boolean) => { + setIsBottomUp(state); + }; + + /* 홈(메인) 행성 고정 */ + const handleFixMainPlanet = () => { + /* TODO: 선택 행성 (selectedId) 메인 행성으로 변경 API 연동 */ + setShowBottom(false); + }; + + /* 행성 삭제 관련 함수 */ const handleDeletePlanet = () => { + setShowBottom(false); setConfirmDeleteModal(true); }; const handleConfirmDeletePlanet = async () => { - if (checkedPlanets.length > 0) { + if (selectedId) { const smallestIndexPlanet = planets - ?.filter((planet) => checkedPlanets.includes(planet.spaceId)) + ?.filter((planet) => selectedId.includes(planet.spaceId)) ?.reduce((prev, curr) => planets.indexOf(prev) < planets.indexOf(curr) ? prev : curr ); /* 행성 삭제하기 */ try { - const response = await deleteSpaces({ spaceIds: checkedPlanets }); - console.log("행성 삭제 성공:", response.data); + const response = await deleteSpaces({ spaceIds: [selectedId] }); + console.log('행성 삭제 성공:', response.data); setPlanets( - planets?.filter((planet) => !checkedPlanets.includes(planet.spaceId)) + (prevPlanets) => + prevPlanets?.filter( + (planet) => !selectedId.includes(planet.spaceId) + ) || [] ); await fetchSpaceList(); + setShowBottom(false); } catch (error) { - console.error("행성 삭제 실패:", error); + console.error('행성 삭제 실패:', error); } setConfirmDeleteModal(false); - setDeleteMode(false); + setDragMode(false); showToast( - `${smallestIndexPlanet?.spaceName} ${ - checkedPlanets.length > 1 ? `외 ${checkedPlanets.length - 1}개` : "" - } 행성과 등록된 편지들이 함께 삭제 되었어요`, + `${smallestIndexPlanet?.spaceName} 행성과 등록된 편지들이 함께 삭제 되었어요`, { icon: false, close: false, - bottom: "65px", + bottom: '65px' } ); } @@ -126,14 +146,14 @@ const PlanetManagePage = () => { setConfirmDeleteModal(false); }; - const onDragEnd = async ({ + const onDragEnd = ({ source, - destination, + destination }: { source: any; destination: any; }) => { - console.log("dragEnd"); + console.log('dragEnd'); if (!destination) return; // destination이 없다면 return console.log(source, destination); @@ -148,21 +168,11 @@ const PlanetManagePage = () => { const newOrder: { spaceId: string; index: number }[] = items.map( (item: Planet, index: number) => ({ spaceId: item.spaceId, - index: index, + index: index }) ); - setChangedOrder(newOrder.map((item) => item.spaceId)); - + setChangedOrder(newOrder); console.log(newOrder); - - /* 스페이스 순서 변경 API 호출 */ - try { - const response = await putSpacesOrder({ orders: newOrder }); - console.log("결과", newOrder); - console.log("스페이스 순서 변경 성공:", response); - } catch (error) { - console.error("스페이스 순서 변경 실패:", error); - } }; return ( @@ -170,20 +180,14 @@ const PlanetManagePage = () => { - - {deleteMode ? ( - - check - 전체 선택 + + {dragMode ? ( + + 편집 완료 ) : ( - - 삭제 + + 순서 편집 )} @@ -199,11 +203,11 @@ const PlanetManagePage = () => { {planets?.map((planet, index) => ( { id={planet.spaceId} planetName={planet.spaceName} count={planet.letterCount} - checked={checkedPlanets} - deleteMode={deleteMode} + dragMode={dragMode} onClick={() => { handleChangeChecked(planet.spaceId); }} - isMain={index === 0} + onShowBottom={() => handleShowBottom(planet.spaceId)} + isMain={planet.isMainSpace} innerRef={provided.innerRef} dragHandleProps={provided.dragHandleProps} draggableProps={provided.draggableProps} - modify={true} /> )} @@ -234,22 +237,33 @@ const PlanetManagePage = () => { )} - {deleteMode && ( - -