feat(admin): 관리자 대시보드와 미디어 자산 UI를 추가
This commit is contained in:
@@ -3,10 +3,15 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import {
|
||||
getSceneBackgroundStyle,
|
||||
getSceneById,
|
||||
SCENE_THEMES,
|
||||
} from '@/entities/scene';
|
||||
import {
|
||||
getSceneStageBackgroundStyle,
|
||||
getSceneStagePhotoUrl,
|
||||
preloadAssetImage,
|
||||
useMediaCatalog,
|
||||
} from '@/entities/media';
|
||||
import {
|
||||
GOAL_CHIPS,
|
||||
SOUND_PRESETS,
|
||||
@@ -16,7 +21,7 @@ import {
|
||||
type TimerPreset,
|
||||
} from '@/entities/session';
|
||||
import { useFocusSessionEngine } from '@/features/focus-session';
|
||||
import { useSoundPresetSelection } from '@/features/sound-preset';
|
||||
import { useSoundPlayback, useSoundPresetSelection } from '@/features/sound-preset';
|
||||
import { useHudStatusLine } from '@/shared/lib/useHudStatusLine';
|
||||
import { SpaceFocusHudWidget } from '@/widgets/space-focus-hud';
|
||||
import { SpaceSetupDrawerWidget } from '@/widgets/space-setup-drawer';
|
||||
@@ -197,6 +202,8 @@ export const SpaceWorkspaceWidget = () => {
|
||||
timer: false,
|
||||
});
|
||||
const queuedFocusStatusMessageRef = useRef<string | null>(null);
|
||||
const lastSoundPlaybackErrorRef = useRef<string | null>(null);
|
||||
const { sceneAssetMap, soundAssetMap } = useMediaCatalog();
|
||||
|
||||
const {
|
||||
selectedPresetId,
|
||||
@@ -223,6 +230,7 @@ export const SpaceWorkspaceWidget = () => {
|
||||
const selectedScene = useMemo(() => {
|
||||
return getSceneById(selectedSceneId) ?? SCENE_THEMES[0];
|
||||
}, [selectedSceneId]);
|
||||
const selectedSceneAsset = sceneAssetMap[selectedScene.id];
|
||||
|
||||
const setupScenes = useMemo(() => {
|
||||
const visibleScenes = SCENE_THEMES.slice(0, 6);
|
||||
@@ -242,6 +250,7 @@ export const SpaceWorkspaceWidget = () => {
|
||||
const canStartSession = canStart && (!currentSession || resolvedPlaybackState !== 'running');
|
||||
const canPauseSession = Boolean(currentSession && resolvedPlaybackState === 'running');
|
||||
const canRestartSession = Boolean(currentSession);
|
||||
const shouldPlaySound = isFocusMode && resolvedPlaybackState === 'running';
|
||||
|
||||
const applyRecommendedSelections = useCallback((
|
||||
sceneId: string,
|
||||
@@ -343,6 +352,21 @@ export const SpaceWorkspaceWidget = () => {
|
||||
};
|
||||
}, [currentSession, selectedPresetId, selectedTimerLabel, setSelectedPresetId]);
|
||||
|
||||
useEffect(() => {
|
||||
const preferMobile =
|
||||
typeof window !== 'undefined' ? window.matchMedia('(max-width: 767px)').matches : false;
|
||||
|
||||
preloadAssetImage(getSceneStagePhotoUrl(selectedScene, selectedSceneAsset, { preferMobile }));
|
||||
}, [selectedScene, selectedSceneAsset]);
|
||||
|
||||
const { error: soundPlaybackError } = useSoundPlayback({
|
||||
selectedPresetId,
|
||||
soundAsset: soundAssetMap[selectedPresetId],
|
||||
masterVolume,
|
||||
isMuted,
|
||||
shouldPlay: shouldPlaySound,
|
||||
});
|
||||
|
||||
const handleSelectScene = (sceneId: string) => {
|
||||
setSelectedSceneId(sceneId);
|
||||
applyRecommendedSelections(sceneId);
|
||||
@@ -601,12 +625,28 @@ export const SpaceWorkspaceWidget = () => {
|
||||
});
|
||||
}, [isFocusMode, pushStatusLine]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!soundPlaybackError) {
|
||||
lastSoundPlaybackErrorRef.current = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (soundPlaybackError === lastSoundPlaybackErrorRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastSoundPlaybackErrorRef.current = soundPlaybackError;
|
||||
pushStatusLine({
|
||||
message: soundPlaybackError,
|
||||
});
|
||||
}, [pushStatusLine, soundPlaybackError]);
|
||||
|
||||
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={getSceneBackgroundStyle(selectedScene)}
|
||||
style={getSceneStageBackgroundStyle(selectedScene, selectedSceneAsset)}
|
||||
/>
|
||||
|
||||
<div className="relative z-10 flex h-full flex-col">
|
||||
@@ -616,6 +656,7 @@ export const SpaceWorkspaceWidget = () => {
|
||||
<SpaceSetupDrawerWidget
|
||||
open={!isFocusMode}
|
||||
scenes={setupScenes}
|
||||
sceneAssetMap={sceneAssetMap}
|
||||
selectedSceneId={selectedScene.id}
|
||||
selectedTimerLabel={selectedTimerLabel}
|
||||
selectedSoundPresetId={selectedPresetId}
|
||||
@@ -686,6 +727,7 @@ export const SpaceWorkspaceWidget = () => {
|
||||
<SpaceToolsDockWidget
|
||||
isFocusMode={isFocusMode}
|
||||
scenes={setupScenes}
|
||||
sceneAssetMap={sceneAssetMap}
|
||||
selectedSceneId={selectedScene.id}
|
||||
selectedTimerLabel={selectedTimerLabel}
|
||||
timerPresets={TIMER_SELECTION_PRESETS}
|
||||
|
||||
Reference in New Issue
Block a user