feat(space): secondary weekly review teaser 추가
This commit is contained in:
@@ -6,14 +6,17 @@ import {
|
||||
preloadAssetImage,
|
||||
useMediaCatalog,
|
||||
} from "@/entities/media";
|
||||
import { usePlanTier } from "@/entities/plan";
|
||||
import { getSceneById, SCENE_THEMES } from "@/entities/scene";
|
||||
import { GOAL_CHIPS, SOUND_PRESETS, useThoughtInbox } from "@/entities/session";
|
||||
import { useFocusSessionEngine } from "@/features/focus-session";
|
||||
import { useFocusStats } from "@/features/stats";
|
||||
import {
|
||||
useSoundPlayback,
|
||||
useSoundPresetSelection,
|
||||
} from "@/features/sound-preset";
|
||||
import { useHudStatusLine } from "@/shared/lib/useHudStatusLine";
|
||||
import { copy } from "@/shared/i18n";
|
||||
import { SpaceFocusHudWidget } from "@/widgets/space-focus-hud";
|
||||
import { SpaceSetupDrawerWidget } from "@/widgets/space-setup-drawer";
|
||||
import { SpaceToolsDockWidget } from "@/widgets/space-tools-dock";
|
||||
@@ -63,6 +66,8 @@ export const SpaceWorkspaceWidget = () => {
|
||||
usedFallbackManifest,
|
||||
hasResolvedManifest,
|
||||
} = useMediaCatalog();
|
||||
const { isPro } = usePlanTier();
|
||||
const { review, summary: weeklySummary } = useFocusStats();
|
||||
|
||||
const initialSceneId = useMemo(
|
||||
() => resolveInitialSceneId(sceneQuery, undefined),
|
||||
@@ -97,6 +102,7 @@ export const SpaceWorkspaceWidget = () => {
|
||||
>("paused");
|
||||
const [pendingSessionEntryPoint, setPendingSessionEntryPoint] =
|
||||
useState<SessionEntryPoint>("space-setup");
|
||||
const [showReviewTeaserAfterComplete, setShowReviewTeaserAfterComplete] = useState(false);
|
||||
|
||||
const {
|
||||
selectedPresetId,
|
||||
@@ -208,6 +214,27 @@ export const SpaceWorkspaceWidget = () => {
|
||||
isBootstrapping,
|
||||
syncCurrentSession,
|
||||
});
|
||||
const hasEnoughWeeklyData =
|
||||
weeklySummary.last7Days.startedSessions >= 3 &&
|
||||
(weeklySummary.last7Days.completedSessions >= 2 ||
|
||||
review.recoveryQuality.availability === "ready");
|
||||
const shouldShowSecondaryReviewTeaser =
|
||||
workspaceMode === "setup" &&
|
||||
showReviewTeaserAfterComplete &&
|
||||
hasEnoughWeeklyData;
|
||||
const secondaryReviewTeaser = shouldShowSecondaryReviewTeaser
|
||||
? {
|
||||
title: isPro
|
||||
? copy.space.setup.reviewTeaserTitlePro
|
||||
: copy.space.setup.reviewTeaserTitle,
|
||||
summary: isPro
|
||||
? review.carryForward.keepDoing
|
||||
: copy.space.setup.reviewTeaserHelper,
|
||||
ctaHref: "/stats?review=weekly&origin=space-complete",
|
||||
ctaLabel: copy.space.setup.reviewTeaserCta,
|
||||
onDismiss: () => setShowReviewTeaserAfterComplete(false),
|
||||
}
|
||||
: undefined;
|
||||
|
||||
useEffect(() => {
|
||||
if (!isBootstrapping && !currentSession && !hasQueryOverrides) {
|
||||
@@ -270,12 +297,17 @@ export const SpaceWorkspaceWidget = () => {
|
||||
}
|
||||
onGoalChange={selection.handleGoalChange}
|
||||
onGoalChipSelect={selection.handleGoalChipSelect}
|
||||
onStart={controls.handleSetupFocusOpen}
|
||||
onStart={() => {
|
||||
setShowReviewTeaserAfterComplete(false);
|
||||
controls.handleSetupFocusOpen();
|
||||
}}
|
||||
reviewTeaser={secondaryReviewTeaser}
|
||||
resumeHint={
|
||||
selection.showResumePrompt && selection.resumeGoal
|
||||
? {
|
||||
goal: selection.resumeGoal,
|
||||
onResume: () => {
|
||||
setShowReviewTeaserAfterComplete(false);
|
||||
selection.setGoalInput(selection.resumeGoal);
|
||||
selection.setSelectedGoalId(null);
|
||||
selection.setShowResumePrompt(false);
|
||||
@@ -285,6 +317,7 @@ export const SpaceWorkspaceWidget = () => {
|
||||
);
|
||||
},
|
||||
onStartFresh: () => {
|
||||
setShowReviewTeaserAfterComplete(false);
|
||||
selection.setGoalInput("");
|
||||
selection.setSelectedGoalId(null);
|
||||
selection.setShowResumePrompt(false);
|
||||
@@ -319,7 +352,15 @@ export const SpaceWorkspaceWidget = () => {
|
||||
onDismissReturnPrompt={awayReturnRecovery.dismissReturnPrompt}
|
||||
onStatusMessage={pushStatusLine}
|
||||
onIntentUpdate={controls.handleIntentUpdate}
|
||||
onGoalFinish={controls.handleGoalComplete}
|
||||
onGoalFinish={async () => {
|
||||
const didFinish = await controls.handleGoalComplete();
|
||||
|
||||
if (didFinish) {
|
||||
setShowReviewTeaserAfterComplete(true);
|
||||
}
|
||||
|
||||
return didFinish;
|
||||
}}
|
||||
onGoalUpdate={controls.handleGoalAdvance}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
Reference in New Issue
Block a user