BREAKING CHANGE: MemoEditor internal architecture completely refactored ## Summary Refactored MemoEditor from hooks-based state management to a three-layer architecture (Presentation → State → Services) using useReducer pattern. ## Changes ### Architecture - **State Layer** (5 new files): types, actions, reducer, context, barrel export - **Service Layer** (6 new files): error, validation, upload, cache, memo services + barrel - **Component Layer** (3 new files): EditorToolbar, EditorContent, EditorMetadata - **Simplified Hooks** (3 new files): useMemoInit, useAutoSave, useKeyboard ### Code Reduction - Main component: ~380 lines → ~140 lines (-63%) - Hooks removed: 5 old hooks (useMemoEditorState, useMemoSave, etc.) - Total lines removed: 508 lines of old code - Utility hooks preserved: 8 hooks still in use (useLocation, useDragAndDrop, etc.) ### Improvements - ✅ Predictable state transitions with useReducer - ✅ Testable business logic in pure service functions - ✅ Cleaner component code (presentation only) - ✅ Better separation of concerns - ✅ Type-safe actions with discriminated unions - ✅ Centralized error handling ## Statistics - Files changed: 26 - Commits created: 25 (squashed into 1) - New files: 17 - Removed files: 5 - TypeScript errors: 0 - Lint errors: 0 ## Testing Manual testing required for: - Editor functionality (create, edit, save) - Drag and drop - Focus mode - Keyboard shortcuts (Cmd/Ctrl + Enter) - Auto-save to localStorage
27 lines
786 B
TypeScript
27 lines
786 B
TypeScript
import type { EditorState } from "../state";
|
|
|
|
export interface ValidationResult {
|
|
valid: boolean;
|
|
reason?: string;
|
|
}
|
|
|
|
export const validationService = {
|
|
canSave(state: EditorState): ValidationResult {
|
|
// Must have content, attachment, or local file
|
|
if (!state.content.trim() && state.metadata.attachments.length === 0 && state.localFiles.length === 0) {
|
|
return { valid: false, reason: "Content, attachment, or file required" };
|
|
}
|
|
|
|
// Cannot save while uploading
|
|
if (state.ui.isLoading.uploading) {
|
|
return { valid: false, reason: "Wait for upload to complete" };
|
|
}
|
|
|
|
// Cannot save while already saving
|
|
if (state.ui.isLoading.saving) {
|
|
return { valid: false, reason: "Save in progress" };
|
|
}
|
|
|
|
return { valid: true };
|
|
},
|
|
};
|