From f8a9347681d4a81a63d2eaa6d1ce8fa5d5fa9645 Mon Sep 17 00:00:00 2001 From: Johannes Millan Date: Mon, 19 Jan 2026 14:48:56 +0100 Subject: [PATCH] feat(focus-mode): add end focus session button to completion banner Adds a secondary "End Focus Session" button to the focus banner when a session completes, allowing users to completely exit focus mode and dismiss the banner instead of only being able to start a break or next session. --- .../store/focus-mode.effects.spec.ts | 5 +-- .../focus-mode/store/focus-mode.effects.ts | 33 ++++++++++++------- src/app/t.const.ts | 1 + src/assets/i18n/en.json | 1 + 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/app/features/focus-mode/store/focus-mode.effects.spec.ts b/src/app/features/focus-mode/store/focus-mode.effects.spec.ts index 5a1a8264e..6ddbd5dad 100644 --- a/src/app/features/focus-mode/store/focus-mode.effects.spec.ts +++ b/src/app/features/focus-mode/store/focus-mode.effects.spec.ts @@ -2790,8 +2790,9 @@ describe('FocusModeEffects', () => { expect(buttonActions.action).toBeDefined(); expect(buttonActions.action.label).toBe('F.FOCUS_MODE.B.START'); - // action2 should be undefined when start button is shown - expect(buttonActions.action2).toBeUndefined(); + // action2 should show "End Focus Session" button when session is completed + expect(buttonActions.action2).toBeDefined(); + expect(buttonActions.action2.label).toBe('F.FOCUS_MODE.B.END_FOCUS_SESSION'); }); it('should have start button when break time is up', () => { diff --git a/src/app/features/focus-mode/store/focus-mode.effects.ts b/src/app/features/focus-mode/store/focus-mode.effects.ts index 91d65f504..5e7ea29ba 100644 --- a/src/app/features/focus-mode/store/focus-mode.effects.ts +++ b/src/app/features/focus-mode/store/focus-mode.effects.ts @@ -974,20 +974,29 @@ export class FocusModeEffects { }; // End session button - complete for work, skip for break (while running) - // Hide when session is completed or break time is up (Start button takes priority) - const endAction = shouldShowStartButton - ? undefined - : isOnBreak + // When session is completed (not break), show "End Focus Session" button + const endAction = + isSessionCompleted && !isBreakTimeUp ? { - label: T.F.FOCUS_MODE.SKIP_BREAK, - ...(useIcons && { icon: 'skip_next' }), - fn: () => this._handleSkipBreak(), - } - : { - label: T.F.FOCUS_MODE.B.END_SESSION, + label: T.F.FOCUS_MODE.B.END_FOCUS_SESSION, ...(useIcons && { icon: 'done_all' }), - fn: () => this._handleEndSession(), - }; + fn: () => { + this.store.dispatch(actions.cancelFocusSession()); + }, + } + : shouldShowStartButton + ? undefined + : isOnBreak + ? { + label: T.F.FOCUS_MODE.SKIP_BREAK, + ...(useIcons && { icon: 'skip_next' }), + fn: () => this._handleSkipBreak(), + } + : { + label: T.F.FOCUS_MODE.B.END_SESSION, + ...(useIcons && { icon: 'done_all' }), + fn: () => this._handleEndSession(), + }; // Open overlay button const overlayAction = { diff --git a/src/app/t.const.ts b/src/app/t.const.ts index 83e7f9a15..93ff2de6d 100644 --- a/src/app/t.const.ts +++ b/src/app/t.const.ts @@ -180,6 +180,7 @@ const T = { ADD_TIME_MINUTE: 'F.FOCUS_MODE.ADD_TIME_MINUTE', B: { BREAK_RUNNING: 'F.FOCUS_MODE.B.BREAK_RUNNING', + END_FOCUS_SESSION: 'F.FOCUS_MODE.B.END_FOCUS_SESSION', END_SESSION: 'F.FOCUS_MODE.B.END_SESSION', PAUSE: 'F.FOCUS_MODE.B.PAUSE', POMODORO_BREAK_RUNNING: 'F.FOCUS_MODE.B.POMODORO_BREAK_RUNNING', diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 1b3e64f14..7b41c2b7a 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -177,6 +177,7 @@ "ADD_TIME_MINUTE": "Add 1 minute", "B": { "BREAK_RUNNING": "Break is running", + "END_FOCUS_SESSION": "End Focus Session", "END_SESSION": "End session", "PAUSE": "Pause", "POMODORO_BREAK_RUNNING": "Break #{{cycleNr}} is running",