feat(space): 종료 결과 모달과 current session thought 복원 추가

This commit is contained in:
2026-03-16 20:08:50 +09:00
parent 6194c19f3b
commit 1d2ce85cfd
10 changed files with 401 additions and 79 deletions

View File

@@ -31,6 +31,22 @@ interface RawAdvanceCurrentGoalResponse {
updatedPlanToday: Parameters<typeof normalizeFocusPlanToday>[0];
}
interface RawCurrentSessionThought {
id: string;
text: string;
sceneName: string;
isCompleted: boolean;
capturedAt: string;
}
interface RawCompletionResult {
completedSessionId: string;
completionSource: 'timer-complete' | 'manual-end';
completedGoal: string;
focusedSeconds: number;
thoughts: RawCurrentSessionThought[];
}
export interface FocusSession {
id: string;
sceneId: string;
@@ -52,6 +68,22 @@ export interface FocusSession {
serverNow: string;
}
export interface CurrentSessionThought {
id: string;
text: string;
sceneName: string;
isCompleted: boolean;
capturedAt: string;
}
export interface CompletionResult {
completedSessionId: string;
completionSource: 'timer-complete' | 'manual-end';
completedGoal: string;
focusedSeconds: number;
thoughts: CurrentSessionThought[];
}
export interface StartFocusSessionRequest {
sceneId: string;
goal: string;
@@ -126,6 +158,23 @@ const normalizeAdvanceGoalResponse = (
};
};
const normalizeCurrentSessionThought = (
thought: RawCurrentSessionThought,
): CurrentSessionThought => {
return {
...thought,
};
};
const normalizeCompletionResult = (
result: RawCompletionResult,
): CompletionResult => {
return {
...result,
thoughts: result.thoughts.map(normalizeCurrentSessionThought),
};
};
export const focusSessionApi = {
getCurrentSession: async (): Promise<FocusSession | null> => {
const response = await apiClient<RawFocusSession | null>('api/v1/focus-sessions/current', {
@@ -135,6 +184,14 @@ export const focusSessionApi = {
return response ? normalizeFocusSession(response) : null;
},
getCurrentSessionThoughts: async (): Promise<CurrentSessionThought[]> => {
const response = await apiClient<RawCurrentSessionThought[]>('api/v1/focus-sessions/current/thoughts', {
method: 'GET',
});
return response.map(normalizeCurrentSessionThought);
},
startSession: async (payload: StartFocusSessionRequest): Promise<FocusSession> => {
const response = await apiClient<RawFocusSession>('api/v1/focus-sessions', {
method: 'POST',
@@ -202,13 +259,13 @@ export const focusSessionApi = {
return normalizeFocusSession(response);
},
completeSession: async (payload: CompleteFocusSessionRequest): Promise<FocusSession> => {
const response = await apiClient<RawFocusSession>('api/v1/focus-sessions/current/complete', {
completeSession: async (payload: CompleteFocusSessionRequest): Promise<CompletionResult> => {
const response = await apiClient<RawCompletionResult>('api/v1/focus-sessions/current/complete', {
method: 'POST',
body: JSON.stringify(payload),
});
return normalizeFocusSession(response);
return normalizeCompletionResult(response);
},
advanceGoal: async (payload: AdvanceCurrentGoalRequest): Promise<AdvanceCurrentGoalResponse> => {

View File

@@ -5,6 +5,7 @@ import { copy } from '@/shared/i18n';
import {
type AdvanceCurrentGoalRequest,
type AdvanceCurrentGoalResponse,
type CompletionResult,
focusSessionApi,
type CompleteFocusSessionRequest,
type FocusSession,
@@ -76,7 +77,7 @@ interface UseFocusSessionEngineResult {
extendCurrentPhase: (payload: { additionalMinutes: number }) => Promise<FocusSession | null>;
updateCurrentIntent: (payload: UpdateCurrentFocusSessionIntentRequest) => Promise<FocusSession | null>;
updateCurrentSelection: (payload: UpdateCurrentFocusSessionSelectionRequest) => Promise<FocusSession | null>;
completeSession: (payload: CompleteFocusSessionRequest) => Promise<FocusSession | null>;
completeSession: (payload: CompleteFocusSessionRequest) => Promise<CompletionResult | null>;
advanceGoal: (payload: AdvanceCurrentGoalRequest) => Promise<AdvanceCurrentGoalResponse | null>;
abandonSession: () => Promise<boolean>;
clearError: () => void;
@@ -279,16 +280,16 @@ export const useFocusSessionEngine = (): UseFocusSessionEngineResult => {
return null;
}
const session = await runMutation(
const result = await runMutation(
() => focusSessionApi.completeSession(payload),
copy.focusSession.completeFailed,
);
if (session) {
if (result) {
applySession(null);
}
return session;
return result;
},
advanceGoal: async (payload) => {
if (!currentSession) {