/** 전략편집기 — 사용자 저장 템플릿 (DB ui_preferences) */ import type { LogicNode } from './strategyTypes'; import type { EditorConditionState } from './strategyConditionSerde'; import { getUiPreferences, patchUiPreferences } from './uiPreferencesDb'; export type UserStrategyTemplate = { id: string; label: string; description?: string; signal: 'buy' | 'sell'; editorState: EditorConditionState; orphans: LogicNode[]; createdAt: number; }; function cloneJson(value: T): T { return JSON.parse(JSON.stringify(value)) as T; } export function createUserTemplateId(): string { return `tmpl-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`; } function parseStored(raw: unknown): UserStrategyTemplate[] { if (!Array.isArray(raw)) return []; return raw.filter( (t): t is UserStrategyTemplate => t != null && typeof t === 'object' && typeof (t as UserStrategyTemplate).id === 'string' && typeof (t as UserStrategyTemplate).label === 'string' && ((t as UserStrategyTemplate).signal === 'buy' || (t as UserStrategyTemplate).signal === 'sell') && typeof (t as UserStrategyTemplate).editorState === 'object' && Array.isArray((t as UserStrategyTemplate).orphans), ); } export function loadUserStrategyTemplates(): UserStrategyTemplate[] { const raw = getUiPreferences().strategyEditor?.userTemplates; return parseStored(raw); } export function saveUserStrategyTemplates(templates: UserStrategyTemplate[]): void { patchUiPreferences({ strategyEditor: { userTemplates: templates } }); } export function addUserStrategyTemplate( input: Omit, ): UserStrategyTemplate { const next: UserStrategyTemplate = { ...input, id: createUserTemplateId(), editorState: cloneJson(input.editorState), orphans: cloneJson(input.orphans), createdAt: Date.now(), }; const templates = [...loadUserStrategyTemplates(), next]; saveUserStrategyTemplates(templates); return next; } export function deleteUserStrategyTemplate(id: string): UserStrategyTemplate[] { const templates = loadUserStrategyTemplates().filter(t => t.id !== id); saveUserStrategyTemplates(templates); return templates; } export function updateUserStrategyTemplate( id: string, patch: Partial>, ): UserStrategyTemplate[] { const templates = loadUserStrategyTemplates().map(t => { if (t.id !== id) return t; return { ...t, ...patch, ...(patch.editorState != null ? { editorState: cloneJson(patch.editorState) } : null), ...(patch.orphans != null ? { orphans: cloneJson(patch.orphans) } : null), }; }); saveUserStrategyTemplates(templates); return templates; } export function loadHiddenBuiltinTemplateIds(): string[] { const raw = getUiPreferences().strategyEditor?.hiddenBuiltinTemplateIds; if (!Array.isArray(raw)) return []; return raw.filter((id): id is string => typeof id === 'string' && id.length > 0); } export function hideBuiltinTemplate(id: string): string[] { const hidden = loadHiddenBuiltinTemplateIds(); if (hidden.includes(id)) return hidden; const next = [...hidden, id]; patchUiPreferences({ strategyEditor: { hiddenBuiltinTemplateIds: next } }); return next; }