From be91f7605081b59a795eaae9e67fefb14e054ac4 Mon Sep 17 00:00:00 2001 From: onebone Date: Sat, 8 Aug 2026 20:20:38 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=ED=95=80=20=EB=93=B1=EB=A1=9D=20?= =?UTF-8?q?=ED=83=9C=EA=B7=B8=20=EC=84=A0=ED=83=9D=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?(#232)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/SongDetailPage.tsx | 58 +++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/src/pages/SongDetailPage.tsx b/src/pages/SongDetailPage.tsx index 3735ce3d..0e9b9672 100644 --- a/src/pages/SongDetailPage.tsx +++ b/src/pages/SongDetailPage.tsx @@ -28,7 +28,10 @@ import { cn } from '@/lib/utils'; import { usePinCreationStore } from '@/store/pinCreationStore'; const INTRO_MAX_LENGTH = 100; +const MIN_TAG_COUNT = 1; const MAX_TAG_COUNT = 4; +const MIN_TAG_ERROR_MESSAGE = '태그를 최소 1개 선택해 주세요.'; +const MAX_TAG_ERROR_MESSAGE = '태그는 최대 4개까지 선택 가능해요.'; const CREATION_TOAST_DURATION_MS = 2_000; const SONG_PREVIEW_PLAY_KEY = 'song-detail-preview'; @@ -458,6 +461,7 @@ export default function SongDetailPage() { const [introduction, setIntroduction] = useState(''); const [selectedTags, setSelectedTags] = useState([]); + const [hasTagLimitError, setHasTagLimitError] = useState(false); const [isFeedPublic, setIsFeedPublic] = useState(true); const [isSongSelectOpen, setIsSongSelectOpen] = useState(false); const [creationToast, setCreationToast] = useState(null); @@ -467,6 +471,12 @@ export default function SongDetailPage() { const coverUrl = preparedTrack?.albumImageUrl || rectangleBg; const waveformPeaks = MOCK_WAVEFORM_PEAKS; const durationMs = preparedTrack?.durationMs ?? MOCK_PREVIEW_DURATION * 1_000; + const hasRequiredTags = selectedTags.length >= MIN_TAG_COUNT; + const tagErrorMessage = hasRequiredTags + ? hasTagLimitError + ? MAX_TAG_ERROR_MESSAGE + : null + : MIN_TAG_ERROR_MESSAGE; const showCreationToast = (message: string) => { setCreationToast((currentToast) => ({ @@ -494,6 +504,11 @@ export default function SongDetailPage() { return; } + if (!hasRequiredTags) { + showCreationToast(MIN_TAG_ERROR_MESSAGE); + return; + } + createPinMutation.mutate( { userLatitude: currentLocation.lat, @@ -520,17 +535,19 @@ export default function SongDetailPage() { }; const toggleTag = (tag: string) => { - setSelectedTags((prev) => { - if (prev.includes(tag)) { - return prev.filter((item) => item !== tag); - } + if (selectedTags.includes(tag)) { + setSelectedTags((currentTags) => currentTags.filter((item) => item !== tag)); + setHasTagLimitError(false); + return; + } - if (prev.length >= MAX_TAG_COUNT) { - return prev; - } + if (selectedTags.length >= MAX_TAG_COUNT) { + setHasTagLimitError(true); + return; + } - return [...prev, tag]; - }); + setSelectedTags((currentTags) => [...currentTags, tag]); + setHasTagLimitError(false); }; if (!place || !currentLocation) { @@ -570,7 +587,8 @@ export default function SongDetailPage() { disabled={ createPinMutation.isPending || playbackPreparationQuery.isPending || - playbackPreparationQuery.isFetching + playbackPreparationQuery.isFetching || + !hasRequiredTags } aria-busy={ createPinMutation.isPending || playbackPreparationQuery.isFetching || undefined @@ -644,10 +662,22 @@ export default function SongDetailPage() {
-

- 태그 (최대 4개) -

-
+
+

+ 태그 (최소 1개) +

+ {tagErrorMessage ? ( +

+ {tagErrorMessage} +

+ ) : null} +
+
{TAG_OPTIONS.map((tag) => { const isSelected = selectedTags.includes(tag);