feat(flow): paused resume gate와 auto-resume 연결

This commit is contained in:
2026-03-15 18:52:19 +09:00
parent 6b70d07e3c
commit 1b01ceaa8b
7 changed files with 94 additions and 21 deletions

View File

@@ -104,6 +104,7 @@ export const SpaceWorkspaceWidget = () => {
const [pendingSessionEntryPoint, setPendingSessionEntryPoint] =
useState<SessionEntryPoint>("space-setup");
const [showReviewTeaserAfterComplete, setShowReviewTeaserAfterComplete] = useState(false);
const [hasConsumedEntryOverlayIntent, setHasConsumedEntryOverlayIntent] = useState(false);
const {
selectedPresetId,
@@ -209,6 +210,7 @@ export const SpaceWorkspaceWidget = () => {
setSelectedGoalId: selection.setSelectedGoalId,
setShowResumePrompt: selection.setShowResumePrompt,
});
const handleStartRequested = controls.handleStartRequested;
const awayReturnRecovery = useAwayReturnRecovery({
currentSession,
@@ -226,6 +228,13 @@ export const SpaceWorkspaceWidget = () => {
const allowsPausedReentry =
resumeIntent === "continue" || resumeIntent === "refocus";
const didResolveEntryRouteRef = useRef(false);
const didHandleResumeIntentRef = useRef(false);
const entryOverlayIntent =
!hasConsumedEntryOverlayIntent &&
resumeIntent === "refocus" &&
currentSession?.state === "paused"
? "resume-refocus"
: null;
const secondaryReviewTeaser = shouldShowSecondaryReviewTeaser
? {
title: isPro
@@ -262,6 +271,28 @@ export const SpaceWorkspaceWidget = () => {
}
}, [allowsPausedReentry, currentSession, isBootstrapping, router]);
useEffect(() => {
if (
isBootstrapping ||
!currentSession ||
currentSession.state !== "paused" ||
didHandleResumeIntentRef.current
) {
return;
}
if (resumeIntent === "continue") {
didHandleResumeIntentRef.current = true;
router.replace("/space");
void handleStartRequested();
return;
}
if (resumeIntent === "refocus") {
return;
}
}, [currentSession, handleStartRequested, isBootstrapping, resumeIntent, router]);
useEffect(() => {
const preferMobile =
typeof window !== "undefined"
@@ -355,14 +386,19 @@ export const SpaceWorkspaceWidget = () => {
hasActiveSession={Boolean(currentSession)}
playbackState={resolvedPlaybackState}
sessionPhase={phase ?? 'focus'}
isSessionActionPending={isSessionMutating}
canStartSession={controls.canStartSession}
canPauseSession={controls.canPauseSession}
canRestartSession={controls.canRestartSession}
returnPromptMode={awayReturnRecovery.returnPromptMode}
onStartRequested={() => {
void controls.handleStartRequested();
}}
isSessionActionPending={isSessionMutating}
canStartSession={controls.canStartSession}
canPauseSession={controls.canPauseSession}
canRestartSession={controls.canRestartSession}
entryOverlayIntent={entryOverlayIntent}
returnPromptMode={awayReturnRecovery.returnPromptMode}
onEntryOverlayIntentHandled={() => {
setHasConsumedEntryOverlayIntent(true);
router.replace("/space");
}}
onStartRequested={() => {
void handleStartRequested();
}}
onPauseRequested={() => {
void controls.handlePauseRequested();
}}