@umituz/react-native-filesystem 2.1.7 → 2.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,51 +1,47 @@
1
1
  {
2
2
  "name": "@umituz/react-native-filesystem",
3
- "version": "2.1.7",
4
- "description": "Domain-Driven Design filesystem utilities for React Native apps with build-time module loading and runtime file operations",
3
+ "version": "2.1.8",
4
+ "description": "File operations and import/export functionality for React Native apps",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
7
+ "exports": {
8
+ ".": "./src/index.ts"
9
+ },
10
+ "files": [
11
+ "src"
12
+ ],
7
13
  "scripts": {
8
- "typecheck": "echo 'TypeScript validation passed'",
9
- "lint": "echo 'Lint passed'",
10
- "version:patch": "npm version patch -m 'chore: release v%s'",
11
- "version:minor": "npm version minor -m 'chore: release v%s'",
12
- "version:major": "npm version major -m 'chore: release v%s'"
14
+ "typecheck": "tsc --noEmit",
15
+ "lint": "eslint src",
16
+ "version:patch": "npm version patch -m 'chore: release v%s'"
13
17
  },
14
18
  "keywords": [
15
19
  "react-native",
16
20
  "filesystem",
17
21
  "file-system",
18
22
  "expo-file-system",
19
- "module-loader",
20
- "require-context",
21
- "directory-tree"
23
+ "download",
24
+ "file-operations"
22
25
  ],
23
26
  "author": "Ümit UZ <umit@umituz.com>",
24
27
  "license": "MIT",
25
28
  "repository": {
26
29
  "type": "git",
27
- "url": "https://github.com/umituz/react-native-filesystem"
30
+ "url": "git+https://github.com/umituz/react-native-filesystem.git"
28
31
  },
29
32
  "peerDependencies": {
30
- "expo-file-system": ">=16.0.0",
31
- "react": ">=18.2.0",
32
- "react-native": ">=0.74.0"
33
+ "expo-file-system": ">=19.0.0",
34
+ "react": ">=18.0.0",
35
+ "react-native": ">=0.70.0"
33
36
  },
34
37
  "devDependencies": {
35
- "@types/node": "^25.0.3",
36
38
  "@types/react": "~19.1.10",
37
- "@types/react-native": "^0.72.8",
38
39
  "expo-file-system": "^19.0.21",
39
40
  "react": "19.1.0",
40
41
  "react-native": "0.81.5",
41
- "typescript": "~5.9.2"
42
+ "typescript": "~5.3.0"
42
43
  },
43
44
  "publishConfig": {
44
45
  "access": "public"
45
- },
46
- "files": [
47
- "src",
48
- "README.md",
49
- "LICENSE"
50
- ]
46
+ }
51
47
  }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Import/Export Types
3
+ * File operations and data transfer functionality
4
+ */
5
+
6
+ export type ExportFormat = "csv" | "json" | "anki" | "xlsx";
7
+ export type ValidationFormat = "json" | "xml" | "yaml";
8
+
9
+ export interface ImportResult {
10
+ success: boolean;
11
+ flashcards: Array<
12
+ Partial<{
13
+ front: string;
14
+ back: string;
15
+ tags?: string[];
16
+ difficulty?: "easy" | "medium" | "hard";
17
+ }>
18
+ >;
19
+ errors: string[];
20
+ warnings: string[];
21
+ duplicatesFound: number;
22
+ importedCount: number;
23
+ }
24
+
25
+ export interface ExportOptions {
26
+ format: ExportFormat;
27
+ includeMedia?: boolean;
28
+ includeTags?: boolean;
29
+ includeProgress?: boolean;
30
+ includeSRS?: boolean;
31
+ compression?: boolean;
32
+ filename?: string;
33
+ }
34
+
35
+ export interface ParsedFlashcard {
36
+ front: string;
37
+ back: string;
38
+ tags?: string[];
39
+ difficulty?: "easy" | "medium" | "hard";
40
+ }
41
+
42
+ export interface MediaUploadProgress {
43
+ fileId: string;
44
+ progress: number; // 0-100
45
+ status: "uploading" | "processing" | "completed" | "error";
46
+ error?: string;
47
+ url?: string;
48
+ }
49
+
50
+ export interface ImportExportService {
51
+ importFlashcards(file: File, format: ExportFormat): Promise<ImportResult>;
52
+ exportFlashcards(
53
+ flashcards: any[],
54
+ options: ExportOptions,
55
+ ): Promise<{
56
+ success: boolean;
57
+ data: Blob;
58
+ filename: string;
59
+ }>;
60
+ validateData(
61
+ data: any,
62
+ format: ValidationFormat,
63
+ ): Promise<{
64
+ isValid: boolean;
65
+ errors: string[];
66
+ warnings: string[];
67
+ }>;
68
+ optimizeData(data: any): Promise<{
69
+ optimized: any;
70
+ compressionRatio: number;
71
+ savings: number;
72
+ }>;
73
+ }
package/src/index.ts CHANGED
@@ -1,178 +1,18 @@
1
1
  /**
2
- * Filesystem Domain - Barrel Export
3
- *
4
- * CENTRAL PLACE FOR ALL FILE OPERATIONS
5
- *
6
- * Provides two main capabilities:
7
- * 1. Build-time module loading (require.context)
8
- * 2. Runtime file operations (expo-file-system)
9
- *
10
- * @domain filesystem
11
- * @enabled true (All apps - Infrastructure domain)
12
- *
13
- * ARCHITECTURE:
14
- * - Domain Layer: Entities (ModuleContext for build-time, File for runtime)
15
- * - Infrastructure Layer: Utils (module loading) + Services (file operations)
16
- *
17
- * ============================================================================
18
- * BUILD-TIME MODULE LOADING (require.context)
19
- * ============================================================================
20
- *
21
- * FEATURES:
22
- * - Auto-discover JSON files in directory
23
- * - Load all modules with single function call
24
- * - Type-safe module loading
25
- * - Metro bundler compatible (React Native)
26
- * - Zero runtime dependencies
27
- * - Build-time resolution (fast)
28
- *
29
- * USAGE - Build-time Module Loading:
30
- *
31
- * Basic Example:
32
- * ```typescript
33
- * import { loadJsonModules } from '@domains/filesystem';
34
- *
35
- * // Auto-load all JSON files in current directory
36
- * const translationContext = require.context('./', false, /\.json$/);
37
- * const translations = loadJsonModules(translationContext);
38
- *
39
- * export default translations;
40
- * // Result: { common: {...}, errors: {...}, settings: {...} }
41
- * ```
42
- *
43
- * Custom Transform Example:
44
- * ```typescript
45
- * import { loadModulesWithTransform } from '@domains/filesystem';
46
- *
47
- * const context = require.context('./', false, /\.json$/);
48
- * const modules = loadModulesWithTransform(context, name => name.toUpperCase());
49
- * // Result: { COMMON: {...}, ERRORS: {...} }
50
- * ```
51
- *
52
- * Get Names Example:
53
- * ```typescript
54
- * import { getModuleNames } from '@domains/filesystem';
55
- *
56
- * const context = require.context('./', false, /\.json$/);
57
- * const names = getModuleNames(context);
58
- * // Result: ['common', 'errors', 'settings']
59
- * ```
60
- *
61
- * ============================================================================
62
- * RUNTIME FILE OPERATIONS (expo-file-system)
63
- * ============================================================================
64
- *
65
- * FEATURES:
66
- * - Read/write files on device
67
- * - Download files from URLs
68
- * - Directory management
69
- * - Cache management
70
- * - File copying/moving
71
- *
72
- * USAGE - Runtime File Operations:
73
- *
74
- * Read/Write Files:
75
- * ```typescript
76
- * import { FileSystemService } from '@domains/filesystem';
77
- *
78
- * // Write file
79
- * const result = await FileSystemService.writeFile(
80
- * FileSystemService.generateFilePath('data.json'),
81
- * JSON.stringify({ key: 'value' })
82
- * );
83
- *
84
- * // Read file
85
- * const content = await FileSystemService.readFile(result.uri);
86
- * ```
87
- *
88
- * Download Files:
89
- * ```typescript
90
- * import { FileSystemService } from '@domains/filesystem';
91
- *
92
- * const result = await FileSystemService.downloadFile(
93
- * 'https://example.com/file.pdf'
94
- * );
95
- * if (result.success) {
96
- * console.log('Downloaded to:', result.uri);
97
- * }
98
- * ```
99
- *
100
- * Directory Operations:
101
- * ```typescript
102
- * import { FileSystemService, FileUtils } from '@domains/filesystem';
103
- *
104
- * // Get document directory
105
- * const docDir = FileSystemService.getDocumentDirectory();
106
- *
107
- * // List files
108
- * const files = await FileSystemService.listDirectory(docDir);
109
- *
110
- * // Clear cache
111
- * await FileSystemService.clearCache();
112
- * ```
113
- *
114
- * File Utilities:
115
- * ```typescript
116
- * import { FileUtils } from '@domains/filesystem';
117
- *
118
- * // Format file size
119
- * const size = FileUtils.formatFileSize(1024000); // "1.00 MB"
120
- *
121
- * // Generate unique filename
122
- * const filename = FileUtils.generateUniqueFilename('photo.jpg');
123
- *
124
- * // Sanitize filename
125
- * const safe = FileUtils.sanitizeFilename('my file!@#.txt'); // "my_file___.txt"
126
- * ```
127
- *
128
- * BENEFITS:
129
- * - Centralized file operations (no duplication)
130
- * - Type-safe with TypeScript
131
- * - Works across all 100+ apps
132
- * - Used by other domains (media, etc.)
133
- * - Clean, maintainable code
134
- *
135
- * @see https://docs.expo.dev/versions/latest/sdk/filesystem/
2
+ * @umituz/react-native-filesystem
3
+ * File operations for React Native apps
136
4
  */
137
5
 
138
- // ============================================================================
139
- // BUILD-TIME MODULE LOADING
140
- // ============================================================================
141
-
142
- // Domain Layer - Module Context Entities
143
- export type {
144
- RequireContext,
145
- ModuleCollection,
146
- FileExtension,
147
- } from './domain/entities/ModuleContext';
148
-
149
- // Infrastructure Layer - Module Loading Utils
150
- export {
151
- loadJsonModules,
152
- loadModulesWithTransform,
153
- getModuleNames,
154
- } from './infrastructure/utils/moduleLoader';
155
-
156
- // ============================================================================
157
- // RUNTIME FILE OPERATIONS
158
- // ============================================================================
159
-
160
- // Domain Layer - File Entities
161
- export type {
162
- FileInfo,
163
- FileOperationResult,
164
- DownloadProgress,
165
- } from './domain/entities/File';
166
-
6
+ // Domain - Types and Utilities
167
7
  export type {
168
8
  FileEncoding,
169
9
  DirectoryType,
170
- } from './domain/entities/File';
10
+ FileOperationResult,
11
+ FileInfo,
12
+ DownloadProgress,
13
+ } from "./domain/entities/File";
171
14
 
172
- export {
173
- FILE_CONSTANTS,
174
- FileUtils,
175
- } from './domain/entities/File';
15
+ export { FILE_CONSTANTS, FileUtils } from "./domain/entities/File";
176
16
 
177
- // Infrastructure Layer - FileSystem Service
178
- export { FileSystemService } from './infrastructure/services/FileSystemService';
17
+ // Services - File Operations
18
+ export { downloadFile } from "./infrastructure/services/download.service";
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Import/Export Service
3
+ * File operations and data transfer functionality
4
+ */
5
+
6
+ import type {
7
+ ExportFormat,
8
+ ValidationFormat,
9
+ ParsedFlashcard,
10
+ ImportResult,
11
+ MediaUploadProgress,
12
+ ImportExportService,
13
+ ParsedFlashcard,
14
+ } from "../../domain/entities/ImportExport.types";
15
+
16
+ export class ImportExportServiceImpl implements ImportExportService {
17
+ private static instance: ImportExportServiceImpl;
18
+
19
+ static getInstance(): ImportExportServiceImpl {
20
+ if (!ImportExportServiceImpl.instance) {
21
+ ImportExportServiceImpl.instance = new ImportExportServiceImpl();
22
+ }
23
+ return ImportExportServiceImpl.instance;
24
+ }
25
+
26
+ async importFlashcards(file: File): Promise<ImportResult> {
27
+ try {
28
+ const format = this.detectFileFormat(file.name);
29
+
30
+ switch (format) {
31
+ case 'csv':
32
+ return await this.importCSV(file);
33
+ case 'json':
34
+ return await this.importJSON(file);
35
+ case 'anki':
36
+ return this.importAnki(file);
37
+ default:
38
+ throw new Error(`Unsupported file format: ${format}`);
39
+ }
40
+ } catch (error) {
41
+ return {
42
+ success: false,
43
+ flashcards: [],
44
+ errors: [error instanceof Error ? error.message : "Import failed"],
45
+ warnings: [],
46
+ duplicatesFound: 0,
47
+ importedCount: 0,
48
+ };
49
+ }
50
+ }
51
+
52
+ async importCSV(file: File): Promise<ImportResult> {
53
+ const text = await file.text();
54
+ const lines = text.split('\n').filter(line => line.trim());
55
+
56
+ if (lines.length < 2) {
57
+ return {
58
+ success: false,
59
+ flashcards: [],
60
+ errors: ["CSV file is empty or invalid"],
61
+ warnings: [],
62
+ duplicatesFound: 0,
63
+ importedCount: 0,
64
+ };
65
+ }
66
+
67
+ const headers = lines[0].split(',').map(h => h.trim().replace(/"/g, ''));
68
+ const flashcards: ParsedFlashcard[] = [];
69
+ const errors: string[] = [];
70
+ let duplicatesFound = 0;
71
+
72
+ for (let i = 1; i < lines.length; i++) {
73
+ try {
74
+ const values = lines[i].split(',').map(v => v.trim().replace(/"/g, ''));
75
+ const flashcard: ParsedFlashcard = {
76
+ front: values[0] || '',
77
+ back: values[1] || '',
78
+ tags: values[2] ? values[2].split(';').map(t => t.trim()) : [],
79
+ difficulty: this.parseDifficulty(values[3]),
80
+ };
81
+
82
+ if (flashcard.front && flashcard.back) {
83
+ // Check for duplicates
84
+ const isDuplicate = flashcards.some(
85
+ existing => existing.front === flashcard.front && existing.back === flashcard.back
86
+ );
87
+
88
+ if (!isDuplicate) {
89
+ flashcards.push(flashcard);
90
+ } else {
91
+ duplicatesFound++;
92
+ errors.push(`Duplicate flashcard found at line ${i + 1}`);
93
+ }
94
+ }
95
+ } catch (error) {
96
+ errors.push(`Line ${i + 1}: ${error}`);
97
+ }
98
+ }
99
+
100
+ return {
101
+ success: errors.length === 0,
102
+ flashcards,
103
+ errors,
104
+ warnings: [],
105
+ duplicatesFound,
106
+ importedCount: flashcards.length,
107
+ };
108
+ }
109
+
110
+ async importJSON(file: File): Promise<ImportResult> {
111
+ try {
112
+ const text = await file.text();
113
+ const data = JSON.parse(text);
114
+
115
+ let flashcards: any[];
116
+
117
+ if (Array.isArray(data)) {
118
+ flashcards = data.map(item => ({
119
+ front: item.front || item.question || '',
120
+ back: item.back || item.answer || '',
121
+ tags: Array.isArray(item.tags) ? item.tags : [],
122
+ difficulty: this.parseDifficulty(item.difficulty),
123
+ }));
124
+ } else if (data.flashcards && Array.isArray(data.flashcards)) {
125
+ flashcards = data.flashcards.map(item => ({
126
+ front: item.front || item.question || '',
127
+ back: item.back || item.answer || '',
128
+ tags: Array.isArray(item.tags) ? item.tags : [],
129
+ difficulty: this.parseDifficulty(item.difficulty),
130
+ }));
131
+ }
132
+
133
+ return {
134
+ success: true,
135
+ flashcards,
136
+ errors: [],
137
+ warnings: [],
138
+ duplicatesFound: 0,
139
+ importedCount: flashcards.length,
140
+ };
141
+ } catch (error) {
142
+ return {
143
+ success: false,
144
+ flashcards: [],
145
+ errors: [`JSON parsing failed: ${error instanceof Error ? error.message : "Unknown error"}`],
146
+ warnings: [],
147
+ duplicatesFound: 0,
148
+ importedCount: 0,
149
+ };
150
+ }
151
+ }
152
+
153
+ async importAnki(file: File): Promise<ImportResult> {
154
+ // Mock Anki import - would require actual APKG parsing in production
155
+ return {
156
+ success: false,
157
+ flashcards: [],
158
+ errors: ["Anki import not yet implemented"],
159
+ warnings: [],
160
+ duplicatesFound: 0,
161
+ importedCount: 0,
162
+ };
163
+ }
164
+
165
+ async exportFlashcards(
166
+ flashcards: any[],
167
+ options: ExportOptions = { format: 'json' }
168
+ ): Promise<{ success: boolean; data: Blob; filename: string }> {
169
+ try {
170
+ const data = flashcards.map(fc => ({
171
+ front: fc.front,
172
+ back: fc.back,
173
+ tags: fc.tags || [],
174
+ difficulty: fc.difficulty || 'medium',
175
+ }));
176
+
177
+ let filename = options.filename || `flashcards_export_${Date.now()}`;
178
+
179
+ switch (options.format) {
180
+ case 'json':
181
+ const jsonData = JSON.stringify(data, null, 2);
182
+ return {
183
+ success: true,
184
+ data: new Blob([jsonData], { type: 'application/json' }),
185
+ filename: filename.endsWith('.json') ? filename : `${filename}.json`,
186
+ };
187
+
188
+ case 'csv':
189
+ const csvData = [
190
+ 'front,back,tags,difficulty',
191
+ ...data.map(fc => [
192
+ `"${fc.front.replace(/"/g, '""')}"`,
193
+ `"${fc.back.replace(/"/g, '""')}"`,
194
+ `"${(fc.tags || []).join(';')}"`,
195
+ `${fc.difficulty || 'medium'}`,
196
+ ]),
197
+ ].join('\n'),
198
+ ];
199
+ return {
200
+ success: true,
201
+ data: new Blob([csvData], { type: 'text/csv' }),
202
+ filename: filename.endsWith('.csv') ? filename : `${filename}.csv`,
203
+ };
204
+
205
+ default:
206
+ throw new Error(`Unsupported export format: ${options.format}`);
207
+ }
208
+ } catch (error) {
209
+ throw new Error(`Export failed: ${error instanceof Error ? error.message : "Unknown error"}`);
210
+ }
211
+ }
212
+
213
+ async validateData(data: any, format: ValidationFormat): Promise<{
214
+ isValid: boolean;
215
+ errors: string[];
216
+ warnings: string[];
217
+ recommendations: string[];
218
+ }> {
219
+ const errors: string[] = [];
220
+ const warnings: string[] = [];
221
+ const recommendations: string[] = [];
222
+
223
+ if (format === 'json') {
224
+ try {
225
+ JSON.parse(data);
226
+ } catch (error) {
227
+ errors.push('Invalid JSON format');
228
+ }
229
+ }
230
+
231
+ if (format === 'csv') {
232
+ const lines = data.split('\n');
233
+ if (lines.length > 10000) {
234
+ warnings.push('Large CSV files may impact performance');
235
+ recommendations.push('Consider splitting large files into smaller chunks');
236
+ }
237
+ }
238
+
239
+ return {
240
+ isValid: errors.length === 0,
241
+ errors,
242
+ warnings,
243
+ recommendations,
244
+ };
245
+ }
246
+
247
+ private detectFileFormat(filename: string): string {
248
+ const extension = filename.split('.').pop()?.toLowerCase();
249
+
250
+ switch (extension) {
251
+ case 'csv': return 'csv';
252
+ case 'json': return 'json';
253
+ case 'apkg': return 'anki';
254
+ case 'txt': return 'csv';
255
+ default: return 'csv';
256
+ }
257
+ }
258
+
259
+ private parseDifficulty(difficulty?: string): 'easy' | 'medium' | 'hard' {
260
+ if (!difficulty) return 'medium';
261
+
262
+ const lower = difficulty.toLowerCase();
263
+ if (lower.includes('easy') || lower === '1') return 'easy';
264
+ if (lower.includes('hard') || lower === '3') return 'hard';
265
+ if (lower.includes('medium') || lower === '2') return 'medium';
266
+ return 'medium';
267
+ }
268
+ }
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Import/Export Hooks
3
+ * React hooks for file operations
4
+ */
5
+
6
+ import React from "react";
7
+ import type {
8
+ ImportResult,
9
+ ExportOptions,
10
+ ParsedFlashcard,
11
+ MediaUploadProgress,
12
+ ImportExportService,
13
+ } from "../../domain/entities/ImportExport.types";
14
+
15
+ export interface UseImportExportResult {
16
+ importFlashcards: (file: File, format: string) => Promise<ImportResult>;
17
+ isImporting: boolean;
18
+ uploadProgress: MediaUploadProgress | null;
19
+ error: string | null;
20
+ }
21
+
22
+ export interface UseExportResult {
23
+ exportFlashcards: (
24
+ flashcards: any[],
25
+ options?: ExportOptions,
26
+ ) => Promise<{
27
+ success: boolean;
28
+ data: Blob;
29
+ filename: string;
30
+ }>;
31
+ isExporting: boolean;
32
+ error: string | null;
33
+ reset: () => void;
34
+ }
35
+
36
+ // Mock React Query implementation
37
+ const useMockQuery = (queryKey: any[], queryFn: any) => {
38
+ const [data, setData] = React.useState<any>(null);
39
+ const [loading, setLoading] = React.useState(true);
40
+ const [error, setError] = React.useState<string | null>(null);
41
+
42
+ React.useEffect(() => {
43
+ queryFn()
44
+ .then(setData)
45
+ .catch(setError)
46
+ .finally(() => setLoading(false));
47
+ }, [queryKey]);
48
+
49
+ return { data, loading, error, refetch: () => {} };
50
+ };
51
+
52
+ export const useImportExport = (): UseImportExportResult => {
53
+ const [isImporting, setIsImporting] = React.useState(false);
54
+ const [uploadProgress, setUploadProgress] =
55
+ React.useState<MediaUploadProgress | null>(null);
56
+ const [error, setError] = React.useState<string | null>(null);
57
+
58
+ const importFlashcards = React.useCallback(
59
+ async (file: File, format: string): Promise<ImportResult> => {
60
+ try {
61
+ setIsImporting(true);
62
+ setError(null);
63
+ setUploadProgress({
64
+ fileId: `import_${Date.now()}`,
65
+ progress: 0,
66
+ status: "uploading",
67
+ });
68
+
69
+ // Simulate import
70
+ await new Promise((resolve) => setTimeout(resolve, 1000));
71
+
72
+ // Mock implementation - would use actual ImportExportService
73
+ const result: ImportResult = {
74
+ success: true,
75
+ flashcards: [
76
+ {
77
+ front: "Sample question 1",
78
+ back: "Sample answer 1",
79
+ difficulty: "easy",
80
+ tags: ["sample", "import"],
81
+ },
82
+ {
83
+ front: "Sample question 2",
84
+ back: "Sample answer 2",
85
+ difficulty: "medium",
86
+ tags: ["sample", "import"],
87
+ },
88
+ ],
89
+ errors: [],
90
+ warnings: [],
91
+ duplicatesFound: 0,
92
+ importedCount: 2,
93
+ };
94
+
95
+ setUploadProgress({
96
+ fileId: `import_${Date.now()}`,
97
+ progress: 100,
98
+ status: "completed",
99
+ });
100
+
101
+ return result;
102
+ } catch (err) {
103
+ const errorMessage =
104
+ err instanceof Error ? err.message : "Import failed";
105
+ setError(errorMessage);
106
+ setIsImporting(false);
107
+
108
+ return {
109
+ success: false,
110
+ flashcards: [],
111
+ errors: [errorMessage],
112
+ warnings: [],
113
+ duplicatesFound: 0,
114
+ importedCount: 0,
115
+ };
116
+ } finally {
117
+ setIsImporting(false);
118
+ }
119
+ },
120
+ [],
121
+ );
122
+
123
+ const exportFlashcards = React.useCallback(
124
+ (
125
+ flashcards: any[],
126
+ options?: ExportOptions = { format: "json" },
127
+ ): Promise<{
128
+ success: boolean;
129
+ data: Blob;
130
+ filename: string;
131
+ }> => {
132
+ try {
133
+ setError(null);
134
+
135
+ // Simulate export
136
+ await new Promise((resolve) => setTimeout(resolve, 1500));
137
+
138
+ const result = {
139
+ success: true,
140
+ data: new Blob([JSON.stringify(flashcards, null, 2)], {
141
+ type: "application/json",
142
+ }),
143
+ filename: options.filename || `flashcards_export_${Date.now()}.json`,
144
+ };
145
+
146
+ return result;
147
+ } catch (err) {
148
+ const errorMessage =
149
+ err instanceof Error ? err.message : "Export failed";
150
+ setError(errorMessage);
151
+
152
+ return {
153
+ success: false,
154
+ data: new Blob(),
155
+ filename: "flashcards_export_error.json",
156
+ };
157
+ }
158
+ },
159
+ [],
160
+ );
161
+
162
+ const reset = React.useCallback(() => {
163
+ setError(null);
164
+ setIsImporting(false);
165
+ setUploadProgress(null);
166
+ }, []);
167
+
168
+ return {
169
+ importFlashcards,
170
+ isImporting,
171
+ uploadProgress,
172
+ error,
173
+ reset,
174
+ };
175
+ };
@@ -1,29 +0,0 @@
1
- /**
2
- * Module Loader Utilities - DEPRECATED
3
- *
4
- * These functions are deprecated and no longer used.
5
- * Kept for backward compatibility only.
6
- */
7
-
8
- import type { ModuleCollection } from '../../domain/entities/ModuleContext';
9
-
10
- /**
11
- * @deprecated No longer used - kept for backward compatibility
12
- */
13
- export function loadJsonModules(): ModuleCollection {
14
- return {};
15
- }
16
-
17
- /**
18
- * @deprecated No longer used - kept for backward compatibility
19
- */
20
- export function loadModulesWithTransform(): ModuleCollection {
21
- return {};
22
- }
23
-
24
- /**
25
- * @deprecated No longer used - kept for backward compatibility
26
- */
27
- export function getModuleNames(): string[] {
28
- return [];
29
- }