Files
viberoom-web/src/widgets/space-tools-dock/model/useSpaceToolsDockHandlers.ts

207 lines
6.2 KiB
TypeScript

'use client';
import { useCallback, useState, type KeyboardEvent as ReactKeyboardEvent } from 'react';
import { usePlanTier } from '@/entities/plan';
import type { RecentThought } from '@/entities/session';
import { copy } from '@/shared/i18n';
import type { HudStatusLinePayload } from '@/shared/lib/useHudStatusLine';
import type { SpaceAnchorPopoverId, SpaceUtilityPanelId } from './types';
interface UseSpaceToolsDockHandlersParams {
setIdle: (idle: boolean) => void;
setOpenPopover: (popover: SpaceAnchorPopoverId | null) => void;
setUtilityPanel: (panel: SpaceUtilityPanelId | null) => void;
onCaptureThought: (note: string) => RecentThought | null;
onDeleteThought: (thoughtId: string) => RecentThought | null;
onSetThoughtCompleted: (thoughtId: string, isCompleted: boolean) => RecentThought | null;
onRestoreThought: (thought: RecentThought) => void;
onRestoreThoughts: (thoughts: RecentThought[]) => void;
onClearInbox: () => RecentThought[];
onStatusMessage: (payload: HudStatusLinePayload) => void;
onSetSoundVolume: (volume: number) => void;
onSetSoundMuted: (muted: boolean) => void;
soundVolume: number;
isSoundMuted: boolean;
showVolumeFeedback: (volume: number) => void;
}
export const useSpaceToolsDockHandlers = ({
setIdle,
setOpenPopover,
setUtilityPanel,
onCaptureThought,
onDeleteThought,
onSetThoughtCompleted,
onRestoreThought,
onRestoreThoughts,
onClearInbox,
onStatusMessage,
onSetSoundVolume,
onSetSoundMuted,
soundVolume,
isSoundMuted,
showVolumeFeedback,
}: UseSpaceToolsDockHandlersParams) => {
const { toolsDock } = copy.space;
const [noteDraft, setNoteDraft] = useState('');
const { plan, setPlan } = usePlanTier();
const openUtilityPanel = useCallback((panel: SpaceUtilityPanelId) => {
setIdle(false);
setOpenPopover(null);
setUtilityPanel(panel);
}, [setIdle, setOpenPopover, setUtilityPanel]);
const handleNoteSubmit = useCallback(() => {
const trimmedNote = noteDraft.trim();
if (!trimmedNote) {
return;
}
const addedThought = onCaptureThought(trimmedNote);
if (!addedThought) {
return;
}
setNoteDraft('');
onStatusMessage({
message: toolsDock.inboxSaved,
durationMs: 4200,
priority: 'undo',
action: {
label: toolsDock.undo,
onClick: () => {
const removed = onDeleteThought(addedThought.id);
if (!removed) {
return;
}
onStatusMessage({ message: toolsDock.inboxSaveUndone });
},
},
});
}, [noteDraft, onCaptureThought, onDeleteThought, onStatusMessage, toolsDock.inboxSaved, toolsDock.inboxSaveUndone, toolsDock.undo]);
const handleInboxComplete = useCallback((thought: RecentThought) => {
onSetThoughtCompleted(thought.id, !thought.isCompleted);
}, [onSetThoughtCompleted]);
const handleInboxDelete = useCallback((thought: RecentThought) => {
const removedThought = onDeleteThought(thought.id);
if (!removedThought) {
return;
}
onStatusMessage({
message: toolsDock.deleted,
durationMs: 4200,
priority: 'undo',
action: {
label: toolsDock.undo,
onClick: () => {
onRestoreThought(removedThought);
onStatusMessage({ message: toolsDock.deleteUndone });
},
},
});
}, [onDeleteThought, onRestoreThought, onStatusMessage, toolsDock.deleted, toolsDock.deleteUndone, toolsDock.undo]);
const handleInboxClear = useCallback(() => {
const snapshot = onClearInbox();
if (snapshot.length === 0) {
onStatusMessage({ message: toolsDock.emptyToClear });
return;
}
onStatusMessage({
message: toolsDock.clearedAll,
durationMs: 4200,
priority: 'undo',
action: {
label: toolsDock.undo,
onClick: () => {
onRestoreThoughts(snapshot);
onStatusMessage({ message: toolsDock.restored });
},
},
});
}, [onClearInbox, onRestoreThoughts, onStatusMessage, toolsDock.clearedAll, toolsDock.emptyToClear, toolsDock.restored, toolsDock.undo]);
const handlePlanPillClick = useCallback(() => {
if (plan === 'pro') {
openUtilityPanel('manage-plan');
return;
}
onStatusMessage({ message: toolsDock.normalPlanInfo });
}, [openUtilityPanel, onStatusMessage, plan, toolsDock.normalPlanInfo]);
const handleLockedClick = useCallback((source: string) => {
onStatusMessage({ message: toolsDock.proFeatureLocked(source) });
openUtilityPanel('paywall');
}, [onStatusMessage, openUtilityPanel, toolsDock]);
const handleSelectProFeature = useCallback((featureId: string) => {
const label =
featureId === 'daily-plan'
? toolsDock.featureLabels.dailyPlan
: featureId === 'rituals'
? toolsDock.featureLabels.rituals
: toolsDock.featureLabels.weeklyReview;
onStatusMessage({ message: toolsDock.proFeaturePending(label) });
}, [onStatusMessage, toolsDock]);
const handleStartPro = useCallback(() => {
setPlan('pro');
onStatusMessage({ message: toolsDock.purchaseMock });
openUtilityPanel('control-center');
}, [onStatusMessage, openUtilityPanel, setPlan, toolsDock.purchaseMock]);
const handleVolumeChange = useCallback((nextVolume: number) => {
const clamped = Math.min(100, Math.max(0, nextVolume));
onSetSoundVolume(clamped);
if (isSoundMuted && clamped > 0) {
onSetSoundMuted(false);
}
showVolumeFeedback(clamped);
}, [isSoundMuted, onSetSoundMuted, onSetSoundVolume, showVolumeFeedback]);
const handleVolumeKeyDown = useCallback((event: ReactKeyboardEvent<HTMLInputElement>) => {
if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') {
return;
}
event.preventDefault();
const step = event.shiftKey ? 10 : 5;
const delta = event.key === 'ArrowRight' ? step : -step;
handleVolumeChange(soundVolume + delta);
}, [handleVolumeChange, soundVolume]);
return {
noteDraft,
setNoteDraft,
plan,
setPlan,
openUtilityPanel,
handleNoteSubmit,
handleInboxComplete,
handleInboxDelete,
handleInboxClear,
handlePlanPillClick,
handleLockedClick,
handleSelectProFeature,
handleStartPro,
handleVolumeChange,
handleVolumeKeyDown,
};
};