feat(stats): recovery 통계를 서버 계약으로 연결
This commit is contained in:
@@ -181,7 +181,8 @@ VibeRoom은 아래 방식으로 진행한다.
|
|||||||
- 1차 snapshot 구현 완료
|
- 1차 snapshot 구현 완료
|
||||||
- `/app -> /stats -> /app` entry flow 구현 완료
|
- `/app -> /stats -> /app` entry flow 구현 완료
|
||||||
- `/space` complete 이후 secondary teaser 구현 완료
|
- `/space` complete 이후 secondary teaser 구현 완료
|
||||||
- 남은 것은 recovery 집계 연결, ritual fit, Free / Pro gating
|
- pause recovery 집계 연결 완료
|
||||||
|
- 남은 것은 away recovery event schema, ritual fit, Free / Pro gating
|
||||||
|
|
||||||
문서:
|
문서:
|
||||||
|
|
||||||
@@ -343,7 +344,7 @@ Away / Return이 끼어들기 전, 다음으로 예정된 축은 아래 두 가
|
|||||||
|
|
||||||
- `Paused Session Re-entry` 구현
|
- `Paused Session Re-entry` 구현
|
||||||
- `/space` recovery browser QA
|
- `/space` recovery browser QA
|
||||||
- Weekly Review recovery 집계 연결
|
- Weekly Review ritual fit highlight
|
||||||
- Premium Ambience System
|
- Premium Ambience System
|
||||||
|
|
||||||
### 방금 완료
|
### 방금 완료
|
||||||
@@ -360,7 +361,7 @@ Away / Return이 끼어들기 전, 다음으로 예정된 축은 아래 두 가
|
|||||||
- `Weekly Review Entry Flow` Slice 4
|
- `Weekly Review Entry Flow` Slice 4
|
||||||
- `/space`에서 goal complete로 setup 상태로 돌아온 직후에만 secondary review teaser가 보인다
|
- `/space`에서 goal complete로 setup 상태로 돌아온 직후에만 secondary review teaser가 보인다
|
||||||
- full review 강제 이동 없이 작은 후행 경로로 `/stats`를 연다
|
- full review 강제 이동 없이 작은 후행 경로로 `/stats`를 연다
|
||||||
- 다음 구현은 weekly review의 실제 recovery 집계 연결이다
|
- 다음 구현은 weekly review의 ritual fit highlight 또는 deeper recovery schema다
|
||||||
- `Paused Session Re-entry` spec
|
- `Paused Session Re-entry` spec
|
||||||
- running / paused / break의 route policy를 한 문서에서 고정했다
|
- running / paused / break의 route policy를 한 문서에서 고정했다
|
||||||
- `/app`은 paused session의 resume gate가 되고, explicit continue 이후 `/space`에서는 자동 resume해야 한다
|
- `/app`은 paused session의 resume gate가 되고, explicit continue 이후 `/space`에서는 자동 resume해야 한다
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ Last Updated: 2026-03-15
|
|||||||
- factual card 반복 중심의 구조를 해체하고 `Weekly Review` 1차 IA로 전환
|
- factual card 반복 중심의 구조를 해체하고 `Weekly Review` 1차 IA로 전환
|
||||||
- `snapshot + start quality + recovery quality + completion quality + carry forward` 구조를 반영
|
- `snapshot + start quality + recovery quality + completion quality + carry forward` 구조를 반영
|
||||||
- 기존 `focus-summary` 응답을 주간 review view model로 변환해서 사용
|
- 기존 `focus-summary` 응답을 주간 review view model로 변환해서 사용
|
||||||
- recovery는 API 집계가 아직 없을 때 limited state로 조용히 표시
|
- recovery는 서버의 `pause 뒤 복귀` 집계를 사용하고, `자리 비움 뒤 복귀`만 limited note로 남긴다
|
||||||
- `/app -> /stats` primary entry의 1차 연결:
|
- `/app -> /stats` primary entry의 1차 연결:
|
||||||
- current session이 없고 최근 7일 데이터가 충분할 때 `/app` hero 아래에 low-emphasis `Weekly Review` teaser를 노출한다
|
- current session이 없고 최근 7일 데이터가 충분할 때 `/app` hero 아래에 low-emphasis `Weekly Review` teaser를 노출한다
|
||||||
- teaser는 `/stats`로 연결되며, hero CTA보다 한 단계 아래 시각 우선순위를 유지한다
|
- teaser는 `/stats`로 연결되며, hero CTA보다 한 단계 아래 시각 우선순위를 유지한다
|
||||||
@@ -129,6 +129,10 @@ Last Updated: 2026-03-15
|
|||||||
- goal complete로 setup 상태로 돌아왔을 때만 setup drawer 아래에 low-emphasis review teaser가 보인다
|
- goal complete로 setup 상태로 돌아왔을 때만 setup drawer 아래에 low-emphasis review teaser가 보인다
|
||||||
- teaser는 `주간 review 보기`로 `/stats`를 열고, 방금 끝낸 흐름 반영을 과장하지 않는 카피만 사용한다
|
- teaser는 `주간 review 보기`로 `/stats`를 열고, 방금 끝낸 흐름 반영을 과장하지 않는 카피만 사용한다
|
||||||
- 다시 시작하거나 dismiss하면 사라지며, live execution 중에는 보이지 않는다
|
- 다시 시작하거나 dismiss하면 사라지며, live execution 중에는 보이지 않는다
|
||||||
|
- `Weekly Review` recovery의 서버 연결:
|
||||||
|
- server `focus-summary` 응답에 `recovery`가 추가됐다
|
||||||
|
- `pause_count / resume_count` 기반 `pause 뒤 복귀`를 실제 수치로 보여준다
|
||||||
|
- 현재는 `away recovery` 이벤트 스키마가 없어 partial/limited 상태로 남긴다
|
||||||
- paywall / plan / landing 메시지 재정렬:
|
- paywall / plan / landing 메시지 재정렬:
|
||||||
- paywall 가치 포인트를 multi-queue, rituals, weekly review 중심으로 재작성
|
- paywall 가치 포인트를 multi-queue, rituals, weekly review 중심으로 재작성
|
||||||
- landing pricing에서 구현되지 않은 1:1 매칭 / 오픈 코워킹 / 팀 대시보드를 메인 판매 포인트에서 제거
|
- landing pricing에서 구현되지 않은 1:1 매칭 / 오픈 코워킹 / 팀 대시보드를 메인 판매 포인트에서 제거
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Last Updated: 2026-03-15
|
|||||||
|
|
||||||
1. `Paused Session Takeover Flow`
|
1. `Paused Session Takeover Flow`
|
||||||
2. `Core Loop Alignment` browser audit
|
2. `Core Loop Alignment` browser audit
|
||||||
3. `Weekly Review` recovery 집계 연결
|
3. `Weekly Review` ritual fit highlight
|
||||||
4. `Premium Ambience`
|
4. `Premium Ambience`
|
||||||
|
|
||||||
## 최근 세션 상태
|
## 최근 세션 상태
|
||||||
@@ -83,7 +83,7 @@ Last Updated: 2026-03-15
|
|||||||
- `/stats`는 factual summary에서 `Weekly Review` 1차 구조로 올라갔다.
|
- `/stats`는 factual summary에서 `Weekly Review` 1차 구조로 올라갔다.
|
||||||
- hero snapshot, start quality, recovery quality, completion quality, carry forward 구조를 사용한다.
|
- hero snapshot, start quality, recovery quality, completion quality, carry forward 구조를 사용한다.
|
||||||
- 기존 `focus-summary` 응답은 review view model로 변환해서 쓴다.
|
- 기존 `focus-summary` 응답은 review view model로 변환해서 쓴다.
|
||||||
- recovery는 API 집계가 아직 없을 때 limited state로 표시한다.
|
- recovery는 서버의 `pause 뒤 복귀` 집계를 사용하고, `away recovery`만 limited state로 남긴다.
|
||||||
- `/app`에서 `/stats`로 들어가는 primary path 1차가 생겼다.
|
- `/app`에서 `/stats`로 들어가는 primary path 1차가 생겼다.
|
||||||
- current session이 없고 최근 7일 데이터가 충분하면 hero 아래에 weekly review teaser가 보인다.
|
- current session이 없고 최근 7일 데이터가 충분하면 hero 아래에 weekly review teaser가 보인다.
|
||||||
- teaser는 `/stats`로 이동시키되, main start CTA보다 낮은 강조로 유지한다.
|
- teaser는 `/stats`로 이동시키되, main start CTA보다 낮은 강조로 유지한다.
|
||||||
@@ -99,7 +99,9 @@ Last Updated: 2026-03-15
|
|||||||
- goal complete로 setup 상태로 돌아왔을 때만 setup drawer 아래에 작은 review teaser가 보인다.
|
- goal complete로 setup 상태로 돌아왔을 때만 setup drawer 아래에 작은 review teaser가 보인다.
|
||||||
- full review 강제 이동 없이 `/stats`를 여는 secondary entry로만 동작한다.
|
- full review 강제 이동 없이 `/stats`를 여는 secondary entry로만 동작한다.
|
||||||
- 방금 끝낸 흐름을 반영한다고 과장하지 않는 카피로 정리했다.
|
- 방금 끝낸 흐름을 반영한다고 과장하지 않는 카피로 정리했다.
|
||||||
- 다음 구현은 weekly review의 실제 recovery 집계 연결이다.
|
- `Weekly Review` recovery의 서버 연결이 들어갔다.
|
||||||
|
- server `focus-summary` 응답에 `recovery`가 추가됐다.
|
||||||
|
- 현재는 `pause 뒤 복귀`만 실집계이며, `자리 비움 뒤 복귀`는 partial note로 남아 있다.
|
||||||
- paused session 재진입 정책을 별도 source of truth로 고정했다.
|
- paused session 재진입 정책을 별도 source of truth로 고정했다.
|
||||||
- `running focus -> /space`
|
- `running focus -> /space`
|
||||||
- `running break -> /space`
|
- `running break -> /space`
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ export interface FocusStatsSummary {
|
|||||||
completedSessions: number;
|
completedSessions: number;
|
||||||
carriedOverCount: number;
|
carriedOverCount: number;
|
||||||
};
|
};
|
||||||
|
recovery: {
|
||||||
|
pausedSessions: number;
|
||||||
|
resumedSessions: number;
|
||||||
|
pauseRecoveryRate: number;
|
||||||
|
awayRecoveryReady: boolean;
|
||||||
|
};
|
||||||
trend: FocusTrendPoint[];
|
trend: FocusTrendPoint[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,12 @@ const buildMockSummary = (): FocusStatsSummary => {
|
|||||||
completedSessions: 4,
|
completedSessions: 4,
|
||||||
carriedOverCount: 1,
|
carriedOverCount: 1,
|
||||||
},
|
},
|
||||||
|
recovery: {
|
||||||
|
pausedSessions: 3,
|
||||||
|
resumedSessions: 2,
|
||||||
|
pauseRecoveryRate: 2 / 3,
|
||||||
|
awayRecoveryReady: true,
|
||||||
|
},
|
||||||
trend: [],
|
trend: [],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -145,6 +151,83 @@ const buildCompletionSummary = (summary: FocusStatsSummary) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const buildRecoverySummary = (summary: FocusStatsSummary, source: StatsSource) => {
|
||||||
|
if (source === 'mock') {
|
||||||
|
return copy.stats.reviewRecoveryMockSummary;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (summary.recovery.pausedSessions === 0) {
|
||||||
|
return copy.stats.reviewRecoveryNoPauseSummary;
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy.stats.reviewRecoveryApiSummary(
|
||||||
|
formatPercent(summary.recovery.pauseRecoveryRate),
|
||||||
|
summary.recovery.resumedSessions,
|
||||||
|
summary.recovery.pausedSessions,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildRecoverySection = (
|
||||||
|
summary: FocusStatsSummary,
|
||||||
|
source: StatsSource,
|
||||||
|
): WeeklyReviewSection => {
|
||||||
|
if (source === 'mock') {
|
||||||
|
return {
|
||||||
|
title: copy.stats.reviewRecoveryTitle,
|
||||||
|
summary: copy.stats.reviewRecoveryMockSummary,
|
||||||
|
availability: 'ready',
|
||||||
|
metrics: [
|
||||||
|
{
|
||||||
|
id: 'recovery-pause',
|
||||||
|
label: copy.stats.reviewPauseRecovery,
|
||||||
|
value: '67%',
|
||||||
|
hint: copy.stats.reviewPauseRecoveryHint,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'recovery-away',
|
||||||
|
label: copy.stats.reviewAwayRecovery,
|
||||||
|
value: '50%',
|
||||||
|
hint: copy.stats.reviewAwayRecoveryHint,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
note: copy.stats.reviewRecoveryMockNote,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const availability = summary.recovery.awayRecoveryReady ? 'ready' : 'limited';
|
||||||
|
const metrics =
|
||||||
|
summary.recovery.pausedSessions > 0
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
id: 'recovery-pause-rate',
|
||||||
|
label: copy.stats.reviewPauseRecovery,
|
||||||
|
value: formatPercent(summary.recovery.pauseRecoveryRate),
|
||||||
|
hint: copy.stats.reviewPauseRecoveryHint,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'recovery-resumed-sessions',
|
||||||
|
label: copy.stats.reviewResumedSessions,
|
||||||
|
value: `${summary.recovery.resumedSessions}${copy.stats.countUnit}`,
|
||||||
|
hint: copy.stats.reviewResumedSessionsHint,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'recovery-paused-sessions',
|
||||||
|
label: copy.stats.reviewPausedSessions,
|
||||||
|
value: `${summary.recovery.pausedSessions}${copy.stats.countUnit}`,
|
||||||
|
hint: copy.stats.reviewPausedSessionsHint,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: copy.stats.reviewRecoveryTitle,
|
||||||
|
summary: buildRecoverySummary(summary, source),
|
||||||
|
availability,
|
||||||
|
metrics,
|
||||||
|
note: availability === 'limited' ? copy.stats.reviewRecoveryPartialNote : undefined,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const buildCarryForward = (summary: FocusStatsSummary): WeeklyReviewViewModel['carryForward'] => {
|
const buildCarryForward = (summary: FocusStatsSummary): WeeklyReviewViewModel['carryForward'] => {
|
||||||
const completionRate =
|
const completionRate =
|
||||||
summary.last7Days.startedSessions > 0
|
summary.last7Days.startedSessions > 0
|
||||||
@@ -255,35 +338,7 @@ const buildReviewFromSummary = (
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
recoveryQuality: {
|
recoveryQuality: buildRecoverySection(summary, source),
|
||||||
title: copy.stats.reviewRecoveryTitle,
|
|
||||||
summary:
|
|
||||||
source === 'mock'
|
|
||||||
? copy.stats.reviewRecoveryMockSummary
|
|
||||||
: copy.stats.reviewRecoveryLimitedSummary,
|
|
||||||
availability: source === 'mock' ? 'ready' : 'limited',
|
|
||||||
metrics:
|
|
||||||
source === 'mock'
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
id: 'recovery-pause',
|
|
||||||
label: copy.stats.reviewPauseRecovery,
|
|
||||||
value: '67%',
|
|
||||||
hint: copy.stats.reviewPauseRecoveryHint,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'recovery-away',
|
|
||||||
label: copy.stats.reviewAwayRecovery,
|
|
||||||
value: '50%',
|
|
||||||
hint: copy.stats.reviewAwayRecoveryHint,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: [],
|
|
||||||
note:
|
|
||||||
source === 'mock'
|
|
||||||
? copy.stats.reviewRecoveryMockNote
|
|
||||||
: copy.stats.reviewRecoveryLimitedNote,
|
|
||||||
},
|
|
||||||
completionQuality: {
|
completionQuality: {
|
||||||
title: copy.stats.reviewCompletionTitle,
|
title: copy.stats.reviewCompletionTitle,
|
||||||
summary: buildCompletionSummary(summary),
|
summary: buildCompletionSummary(summary),
|
||||||
|
|||||||
@@ -52,11 +52,17 @@ export const app = {
|
|||||||
reviewBestDayHint: (minutes: number) => `${minutes}분 동안 가장 오래 집중했어요.`,
|
reviewBestDayHint: (minutes: number) => `${minutes}분 동안 가장 오래 집중했어요.`,
|
||||||
reviewRecoveryTitle: '복귀 품질',
|
reviewRecoveryTitle: '복귀 품질',
|
||||||
reviewRecoveryMockSummary: '이번 주에는 pause 뒤에도 다시 올라탄 흐름이 있었어요. 복귀는 적었지만 분명히 존재했어요.',
|
reviewRecoveryMockSummary: '이번 주에는 pause 뒤에도 다시 올라탄 흐름이 있었어요. 복귀는 적었지만 분명히 존재했어요.',
|
||||||
reviewRecoveryLimitedSummary: '복귀 패턴은 아직 이 review에 충분히 합쳐지지 않았어요. 지금은 시작과 마무리 흐름을 먼저 봅니다.',
|
reviewRecoveryNoPauseSummary: '이번 주에는 pause가 거의 없어 복귀보다 시작과 마무리 흐름이 더 선명했어요.',
|
||||||
|
reviewRecoveryApiSummary: (rate: string, resumedSessions: number, pausedSessions: number) =>
|
||||||
|
`이번 주엔 pause가 있었던 ${pausedSessions}개 세션 중 ${resumedSessions}개를 다시 이어갔어요. pause 뒤 복귀율은 ${rate}였어요.`,
|
||||||
reviewRecoveryMockNote: 'mock 기준으로 pause 뒤 복귀와 away 뒤 복귀를 함께 보여줍니다.',
|
reviewRecoveryMockNote: 'mock 기준으로 pause 뒤 복귀와 away 뒤 복귀를 함께 보여줍니다.',
|
||||||
reviewRecoveryLimitedNote: 'pause / away 복귀 집계는 다음 연결 단계에서 이 review에 포함됩니다.',
|
reviewRecoveryPartialNote: '현재는 pause 뒤 복귀만 집계하고 있어요. 자리 비움 뒤 복귀는 다음 서버 연결 단계에서 추가됩니다.',
|
||||||
reviewPauseRecovery: 'pause 뒤 복귀',
|
reviewPauseRecovery: 'pause 뒤 복귀',
|
||||||
reviewPauseRecoveryHint: '멈춘 뒤 다시 돌아온 비율',
|
reviewPauseRecoveryHint: '멈춘 뒤 다시 돌아온 비율',
|
||||||
|
reviewResumedSessions: '다시 이어간 세션',
|
||||||
|
reviewResumedSessionsHint: 'pause가 있었던 세션 중 다시 focus로 돌아온 세션',
|
||||||
|
reviewPausedSessions: '멈춘 세션',
|
||||||
|
reviewPausedSessionsHint: 'pause가 한 번 이상 있었던 세션',
|
||||||
reviewAwayRecovery: '자리 비움 뒤 복귀',
|
reviewAwayRecovery: '자리 비움 뒤 복귀',
|
||||||
reviewAwayRecoveryHint: '앱을 떠났다가 다시 돌아온 비율',
|
reviewAwayRecoveryHint: '앱을 떠났다가 다시 돌아온 비율',
|
||||||
reviewCompletionTitle: '마무리 품질',
|
reviewCompletionTitle: '마무리 품질',
|
||||||
|
|||||||
@@ -52,11 +52,17 @@ export const stats = {
|
|||||||
reviewBestDayHint: (minutes: number) => `${minutes}분 동안 가장 오래 집중했어요.`,
|
reviewBestDayHint: (minutes: number) => `${minutes}분 동안 가장 오래 집중했어요.`,
|
||||||
reviewRecoveryTitle: '복귀 품질',
|
reviewRecoveryTitle: '복귀 품질',
|
||||||
reviewRecoveryMockSummary: '이번 주에는 pause 뒤에도 다시 올라탄 흐름이 있었어요. 복귀는 적었지만 분명히 존재했어요.',
|
reviewRecoveryMockSummary: '이번 주에는 pause 뒤에도 다시 올라탄 흐름이 있었어요. 복귀는 적었지만 분명히 존재했어요.',
|
||||||
reviewRecoveryLimitedSummary: '복귀 패턴은 아직 이 review에 충분히 합쳐지지 않았어요. 지금은 시작과 마무리 흐름을 먼저 봅니다.',
|
reviewRecoveryNoPauseSummary: '이번 주에는 pause가 거의 없어 복귀보다 시작과 마무리 흐름이 더 선명했어요.',
|
||||||
|
reviewRecoveryApiSummary: (rate: string, resumedSessions: number, pausedSessions: number) =>
|
||||||
|
`이번 주엔 pause가 있었던 ${pausedSessions}개 세션 중 ${resumedSessions}개를 다시 이어갔어요. pause 뒤 복귀율은 ${rate}였어요.`,
|
||||||
reviewRecoveryMockNote: 'mock 기준으로 pause 뒤 복귀와 away 뒤 복귀를 함께 보여줍니다.',
|
reviewRecoveryMockNote: 'mock 기준으로 pause 뒤 복귀와 away 뒤 복귀를 함께 보여줍니다.',
|
||||||
reviewRecoveryLimitedNote: 'pause / away 복귀 집계는 다음 연결 단계에서 이 review에 포함됩니다.',
|
reviewRecoveryPartialNote: '현재는 pause 뒤 복귀만 집계하고 있어요. 자리 비움 뒤 복귀는 다음 서버 연결 단계에서 추가됩니다.',
|
||||||
reviewPauseRecovery: 'pause 뒤 복귀',
|
reviewPauseRecovery: 'pause 뒤 복귀',
|
||||||
reviewPauseRecoveryHint: '멈춘 뒤 다시 돌아온 비율',
|
reviewPauseRecoveryHint: '멈춘 뒤 다시 돌아온 비율',
|
||||||
|
reviewResumedSessions: '다시 이어간 세션',
|
||||||
|
reviewResumedSessionsHint: 'pause가 있었던 세션 중 다시 focus로 돌아온 세션',
|
||||||
|
reviewPausedSessions: '멈춘 세션',
|
||||||
|
reviewPausedSessionsHint: 'pause가 한 번 이상 있었던 세션',
|
||||||
reviewAwayRecovery: '자리 비움 뒤 복귀',
|
reviewAwayRecovery: '자리 비움 뒤 복귀',
|
||||||
reviewAwayRecoveryHint: '앱을 떠났다가 다시 돌아온 비율',
|
reviewAwayRecoveryHint: '앱을 떠났다가 다시 돌아온 비율',
|
||||||
reviewCompletionTitle: '마무리 품질',
|
reviewCompletionTitle: '마무리 품질',
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ export const FocusDashboardWidget = () => {
|
|||||||
const hasEnoughWeeklyData =
|
const hasEnoughWeeklyData =
|
||||||
weeklySummary.last7Days.startedSessions >= 3 &&
|
weeklySummary.last7Days.startedSessions >= 3 &&
|
||||||
(weeklySummary.last7Days.completedSessions >= 2 ||
|
(weeklySummary.last7Days.completedSessions >= 2 ||
|
||||||
review.recoveryQuality.availability === 'ready');
|
weeklySummary.recovery.pausedSessions > 0);
|
||||||
const reviewSource = searchParams.get('review');
|
const reviewSource = searchParams.get('review');
|
||||||
const reviewCarryHint = searchParams.get('carryHint');
|
const reviewCarryHint = searchParams.get('carryHint');
|
||||||
const normalizedReviewCarryHint: ReviewCarryHint | null =
|
const normalizedReviewCarryHint: ReviewCarryHint | null =
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ export const SpaceWorkspaceWidget = () => {
|
|||||||
const hasEnoughWeeklyData =
|
const hasEnoughWeeklyData =
|
||||||
weeklySummary.last7Days.startedSessions >= 3 &&
|
weeklySummary.last7Days.startedSessions >= 3 &&
|
||||||
(weeklySummary.last7Days.completedSessions >= 2 ||
|
(weeklySummary.last7Days.completedSessions >= 2 ||
|
||||||
review.recoveryQuality.availability === "ready");
|
weeklySummary.recovery.pausedSessions > 0);
|
||||||
const shouldShowSecondaryReviewTeaser =
|
const shouldShowSecondaryReviewTeaser =
|
||||||
workspaceMode === "setup" &&
|
workspaceMode === "setup" &&
|
||||||
showReviewTeaserAfterComplete &&
|
showReviewTeaserAfterComplete &&
|
||||||
|
|||||||
Reference in New Issue
Block a user