refactor(space): scene 도메인과 current session 계약을 정리
This commit is contained in:
@@ -3,10 +3,10 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import {
|
||||
getRoomBackgroundStyle,
|
||||
getRoomById,
|
||||
ROOM_THEMES,
|
||||
} from '@/entities/room';
|
||||
getSceneBackgroundStyle,
|
||||
getSceneById,
|
||||
SCENE_THEMES,
|
||||
} from '@/entities/scene';
|
||||
import {
|
||||
GOAL_CHIPS,
|
||||
SOUND_PRESETS,
|
||||
@@ -62,16 +62,16 @@ const readStoredWorkspaceSelection = (): StoredWorkspaceSelection => {
|
||||
}
|
||||
};
|
||||
|
||||
const resolveInitialRoomId = (roomIdFromQuery: string | null, storedSceneId?: string) => {
|
||||
if (roomIdFromQuery && getRoomById(roomIdFromQuery)) {
|
||||
return roomIdFromQuery;
|
||||
const resolveInitialSceneId = (sceneIdFromQuery: string | null, storedSceneId?: string) => {
|
||||
if (sceneIdFromQuery && getSceneById(sceneIdFromQuery)) {
|
||||
return sceneIdFromQuery;
|
||||
}
|
||||
|
||||
if (storedSceneId && getRoomById(storedSceneId)) {
|
||||
if (storedSceneId && getSceneById(storedSceneId)) {
|
||||
return storedSceneId;
|
||||
}
|
||||
|
||||
return ROOM_THEMES[0].id;
|
||||
return SCENE_THEMES[0].id;
|
||||
};
|
||||
|
||||
const resolveInitialSoundPreset = (
|
||||
@@ -150,11 +150,11 @@ const resolveFocusTimeDisplayFromTimerLabel = (timerLabel: string) => {
|
||||
|
||||
export const SpaceWorkspaceWidget = () => {
|
||||
const searchParams = useSearchParams();
|
||||
const roomQuery = searchParams.get('room');
|
||||
const sceneQuery = searchParams.get('scene') ?? searchParams.get('room');
|
||||
const goalQuery = searchParams.get('goal')?.trim() ?? '';
|
||||
const soundQuery = searchParams.get('sound');
|
||||
const timerQuery = searchParams.get('timer');
|
||||
const hasQueryOverrides = Boolean(roomQuery || goalQuery || soundQuery || timerQuery);
|
||||
const hasQueryOverrides = Boolean(sceneQuery || goalQuery || soundQuery || timerQuery);
|
||||
const {
|
||||
thoughts,
|
||||
thoughtCount,
|
||||
@@ -166,22 +166,22 @@ export const SpaceWorkspaceWidget = () => {
|
||||
setThoughtCompleted,
|
||||
} = useThoughtInbox();
|
||||
|
||||
const initialRoomId = resolveInitialRoomId(roomQuery, undefined);
|
||||
const initialRoom = getRoomById(initialRoomId) ?? ROOM_THEMES[0];
|
||||
const initialSceneId = resolveInitialSceneId(sceneQuery, undefined);
|
||||
const initialScene = getSceneById(initialSceneId) ?? SCENE_THEMES[0];
|
||||
const initialGoal = goalQuery;
|
||||
const initialSoundPresetId = resolveInitialSoundPreset(
|
||||
soundQuery,
|
||||
undefined,
|
||||
initialRoom.recommendedSoundPresetId,
|
||||
initialScene.recommendedSoundPresetId,
|
||||
);
|
||||
const initialTimerLabel = resolveInitialTimerLabel(
|
||||
timerQuery,
|
||||
undefined,
|
||||
initialRoom.recommendedTimerPresetId,
|
||||
initialScene.recommendedTimerPresetId,
|
||||
);
|
||||
|
||||
const [workspaceMode, setWorkspaceMode] = useState<WorkspaceMode>('setup');
|
||||
const [selectedRoomId, setSelectedRoomId] = useState(initialRoomId);
|
||||
const [selectedSceneId, setSelectedSceneId] = useState(initialSceneId);
|
||||
const [selectedTimerLabel, setSelectedTimerLabel] = useState(initialTimerLabel);
|
||||
const [goalInput, setGoalInput] = useState(initialGoal);
|
||||
const [selectedGoalId, setSelectedGoalId] = useState<string | null>(null);
|
||||
@@ -216,19 +216,19 @@ export const SpaceWorkspaceWidget = () => {
|
||||
abandonSession,
|
||||
} = useFocusSessionEngine();
|
||||
|
||||
const selectedRoom = useMemo(() => {
|
||||
return getRoomById(selectedRoomId) ?? ROOM_THEMES[0];
|
||||
}, [selectedRoomId]);
|
||||
const selectedScene = useMemo(() => {
|
||||
return getSceneById(selectedSceneId) ?? SCENE_THEMES[0];
|
||||
}, [selectedSceneId]);
|
||||
|
||||
const setupRooms = useMemo(() => {
|
||||
const visibleRooms = ROOM_THEMES.slice(0, 6);
|
||||
const setupScenes = useMemo(() => {
|
||||
const visibleScenes = SCENE_THEMES.slice(0, 6);
|
||||
|
||||
if (visibleRooms.some((room) => room.id === selectedRoom.id)) {
|
||||
return visibleRooms;
|
||||
if (visibleScenes.some((scene) => scene.id === selectedScene.id)) {
|
||||
return visibleScenes;
|
||||
}
|
||||
|
||||
return [selectedRoom, ...visibleRooms].slice(0, 6);
|
||||
}, [selectedRoom]);
|
||||
return [selectedScene, ...visibleScenes].slice(0, 6);
|
||||
}, [selectedScene]);
|
||||
|
||||
const canStart = goalInput.trim().length > 0;
|
||||
const isFocusMode = workspaceMode === 'focus';
|
||||
@@ -237,17 +237,17 @@ export const SpaceWorkspaceWidget = () => {
|
||||
const resolvedTimeDisplay = timeDisplay ?? resolveFocusTimeDisplayFromTimerLabel(selectedTimerLabel);
|
||||
|
||||
const applyRecommendedSelections = useCallback((
|
||||
roomId: string,
|
||||
sceneId: string,
|
||||
overrideState: SelectionOverride = selectionOverride,
|
||||
) => {
|
||||
const room = getRoomById(roomId);
|
||||
const scene = getSceneById(sceneId);
|
||||
|
||||
if (!room) {
|
||||
if (!scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!overrideState.timer) {
|
||||
const recommendedTimerLabel = resolveTimerLabelFromPresetId(room.recommendedTimerPresetId);
|
||||
const recommendedTimerLabel = resolveTimerLabelFromPresetId(scene.recommendedTimerPresetId);
|
||||
|
||||
if (recommendedTimerLabel) {
|
||||
setSelectedTimerLabel(recommendedTimerLabel);
|
||||
@@ -256,9 +256,9 @@ export const SpaceWorkspaceWidget = () => {
|
||||
|
||||
if (
|
||||
!overrideState.sound &&
|
||||
SOUND_PRESETS.some((preset) => preset.id === room.recommendedSoundPresetId)
|
||||
SOUND_PRESETS.some((preset) => preset.id === scene.recommendedSoundPresetId)
|
||||
) {
|
||||
setSelectedPresetId(room.recommendedSoundPresetId);
|
||||
setSelectedPresetId(scene.recommendedSoundPresetId);
|
||||
}
|
||||
}, [selectionOverride, setSelectedPresetId]);
|
||||
|
||||
@@ -268,8 +268,8 @@ export const SpaceWorkspaceWidget = () => {
|
||||
sound: Boolean(storedSelection.override?.sound),
|
||||
timer: Boolean(storedSelection.override?.timer),
|
||||
};
|
||||
const restoredRoomId =
|
||||
!roomQuery && storedSelection.sceneId && getRoomById(storedSelection.sceneId)
|
||||
const restoredSceneId =
|
||||
!sceneQuery && storedSelection.sceneId && getSceneById(storedSelection.sceneId)
|
||||
? storedSelection.sceneId
|
||||
: null;
|
||||
const restoredTimerLabel = !timerQuery
|
||||
@@ -283,8 +283,8 @@ export const SpaceWorkspaceWidget = () => {
|
||||
const rafId = window.requestAnimationFrame(() => {
|
||||
setSelectionOverride(restoredSelectionOverride);
|
||||
|
||||
if (restoredRoomId) {
|
||||
setSelectedRoomId(restoredRoomId);
|
||||
if (restoredSceneId) {
|
||||
setSelectedSceneId(restoredSceneId);
|
||||
}
|
||||
|
||||
if (restoredTimerLabel) {
|
||||
@@ -306,7 +306,7 @@ export const SpaceWorkspaceWidget = () => {
|
||||
return () => {
|
||||
window.cancelAnimationFrame(rafId);
|
||||
};
|
||||
}, [goalQuery, hasQueryOverrides, roomQuery, setSelectedPresetId, soundQuery, timerQuery]);
|
||||
}, [goalQuery, hasQueryOverrides, sceneQuery, setSelectedPresetId, soundQuery, timerQuery]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentSession) {
|
||||
@@ -321,7 +321,7 @@ export const SpaceWorkspaceWidget = () => {
|
||||
? currentSession.soundPresetId
|
||||
: selectedPresetId;
|
||||
const rafId = window.requestAnimationFrame(() => {
|
||||
setSelectedRoomId(currentSession.roomId);
|
||||
setSelectedSceneId(currentSession.sceneId);
|
||||
setSelectedTimerLabel(nextTimerLabel);
|
||||
setSelectedPresetId(nextSoundPresetId);
|
||||
setGoalInput(currentSession.goal);
|
||||
@@ -336,9 +336,9 @@ export const SpaceWorkspaceWidget = () => {
|
||||
};
|
||||
}, [currentSession, selectedPresetId, selectedTimerLabel, setSelectedPresetId]);
|
||||
|
||||
const handleSelectRoom = (roomId: string) => {
|
||||
setSelectedRoomId(roomId);
|
||||
applyRecommendedSelections(roomId);
|
||||
const handleSelectScene = (sceneId: string) => {
|
||||
setSelectedSceneId(sceneId);
|
||||
applyRecommendedSelections(sceneId);
|
||||
};
|
||||
|
||||
const handleSelectTimer = (timerLabel: string, markOverride = false) => {
|
||||
@@ -407,7 +407,7 @@ export const SpaceWorkspaceWidget = () => {
|
||||
setWorkspaceMode('focus');
|
||||
|
||||
const startedSession = await startSession({
|
||||
roomId: selectedRoomId,
|
||||
sceneId: selectedSceneId,
|
||||
goal: trimmedGoal,
|
||||
timerPresetId,
|
||||
soundPresetId: selectedPresetId,
|
||||
@@ -552,21 +552,21 @@ export const SpaceWorkspaceWidget = () => {
|
||||
window.localStorage.setItem(
|
||||
WORKSPACE_SELECTION_STORAGE_KEY,
|
||||
JSON.stringify({
|
||||
sceneId: selectedRoomId,
|
||||
sceneId: selectedSceneId,
|
||||
timerPresetId,
|
||||
soundPresetId: selectedPresetId,
|
||||
goal: normalizedGoal,
|
||||
override: selectionOverride,
|
||||
}),
|
||||
);
|
||||
}, [goalInput, hasHydratedSelection, resumeGoal, selectedRoomId, selectedTimerLabel, selectedPresetId, selectionOverride, showResumePrompt]);
|
||||
}, [goalInput, hasHydratedSelection, resumeGoal, selectedSceneId, selectedTimerLabel, selectedPresetId, selectionOverride, showResumePrompt]);
|
||||
|
||||
return (
|
||||
<div className="relative h-dvh overflow-hidden text-white">
|
||||
<div
|
||||
aria-hidden
|
||||
className="absolute inset-0 bg-cover bg-center will-change-transform animate-[space-stage-pan_42s_ease-in-out_infinite_alternate] motion-reduce:animate-none"
|
||||
style={getRoomBackgroundStyle(selectedRoom)}
|
||||
style={getSceneBackgroundStyle(selectedScene)}
|
||||
/>
|
||||
|
||||
<div className="relative z-10 flex h-full flex-col">
|
||||
@@ -575,8 +575,8 @@ export const SpaceWorkspaceWidget = () => {
|
||||
|
||||
<SpaceSetupDrawerWidget
|
||||
open={!isFocusMode}
|
||||
rooms={setupRooms}
|
||||
selectedRoomId={selectedRoom.id}
|
||||
scenes={setupScenes}
|
||||
selectedSceneId={selectedScene.id}
|
||||
selectedTimerLabel={selectedTimerLabel}
|
||||
selectedSoundPresetId={selectedPresetId}
|
||||
goalInput={goalInput}
|
||||
@@ -585,7 +585,7 @@ export const SpaceWorkspaceWidget = () => {
|
||||
soundPresets={SOUND_PRESETS}
|
||||
timerPresets={TIMER_SELECTION_PRESETS}
|
||||
canStart={canStart}
|
||||
onRoomSelect={handleSelectRoom}
|
||||
onSceneSelect={handleSelectScene}
|
||||
onTimerSelect={(timerLabel) => handleSelectTimer(timerLabel, true)}
|
||||
onSoundSelect={(presetId) => handleSelectSound(presetId, true)}
|
||||
onGoalChange={handleGoalChange}
|
||||
@@ -641,23 +641,23 @@ export const SpaceWorkspaceWidget = () => {
|
||||
|
||||
<SpaceToolsDockWidget
|
||||
isFocusMode={isFocusMode}
|
||||
rooms={setupRooms}
|
||||
selectedRoomId={selectedRoom.id}
|
||||
scenes={setupScenes}
|
||||
selectedSceneId={selectedScene.id}
|
||||
selectedTimerLabel={selectedTimerLabel}
|
||||
timerPresets={TIMER_SELECTION_PRESETS}
|
||||
thoughts={thoughts}
|
||||
thoughtCount={thoughtCount}
|
||||
selectedPresetId={selectedPresetId}
|
||||
onRoomSelect={handleSelectRoom}
|
||||
onSceneSelect={handleSelectScene}
|
||||
onTimerSelect={(timerLabel) => handleSelectTimer(timerLabel, true)}
|
||||
onQuickSoundSelect={(presetId) => handleSelectSound(presetId, true)}
|
||||
sceneRecommendedSoundLabel={selectedRoom.recommendedSound}
|
||||
sceneRecommendedTimerLabel={resolveTimerLabelFromPresetId(selectedRoom.recommendedTimerPresetId) ?? selectedTimerLabel}
|
||||
sceneRecommendedSoundLabel={selectedScene.recommendedSound}
|
||||
sceneRecommendedTimerLabel={resolveTimerLabelFromPresetId(selectedScene.recommendedTimerPresetId) ?? selectedTimerLabel}
|
||||
soundVolume={masterVolume}
|
||||
onSetSoundVolume={setMasterVolume}
|
||||
isSoundMuted={isMuted}
|
||||
onSetSoundMuted={setMuted}
|
||||
onCaptureThought={(note) => addThought(note, selectedRoom.name)}
|
||||
onCaptureThought={(note) => addThought(note, selectedScene.name)}
|
||||
onDeleteThought={removeThought}
|
||||
onSetThoughtCompleted={setThoughtCompleted}
|
||||
onRestoreThought={restoreThought}
|
||||
|
||||
Reference in New Issue
Block a user