@umituz/react-native-design-system 2.8.7 → 2.8.9
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 +10 -6
- package/src/device/infrastructure/repositories/LegacyDeviceIdRepository.ts +1 -1
- package/src/device/infrastructure/services/DeviceFeatureService.ts +1 -1
- package/src/exception/infrastructure/services/ExceptionLogger.ts +1 -1
- package/src/exception/infrastructure/storage/ExceptionStore.ts +1 -1
- package/src/exports/filesystem.ts +1 -0
- package/src/exports/media.ts +1 -0
- package/src/exports/storage.ts +1 -0
- package/src/filesystem/domain/constants/FileConstants.ts +20 -0
- package/src/filesystem/domain/entities/File.ts +20 -0
- package/src/filesystem/domain/types/FileTypes.ts +43 -0
- package/src/filesystem/domain/utils/FileUtils.ts +86 -0
- package/src/filesystem/index.ts +23 -0
- package/src/filesystem/infrastructure/services/FileSystemService.ts +45 -0
- package/src/filesystem/infrastructure/services/cache.service.ts +48 -0
- package/src/filesystem/infrastructure/services/directory.service.ts +66 -0
- package/src/filesystem/infrastructure/services/download.constants.ts +6 -0
- package/src/filesystem/infrastructure/services/download.service.ts +74 -0
- package/src/filesystem/infrastructure/services/download.types.ts +7 -0
- package/src/filesystem/infrastructure/services/encoding.service.ts +25 -0
- package/src/filesystem/infrastructure/services/file-info.service.ts +52 -0
- package/src/filesystem/infrastructure/services/file-manager.service.ts +81 -0
- package/src/filesystem/infrastructure/services/file-path.service.ts +22 -0
- package/src/filesystem/infrastructure/services/file-reader.service.ts +52 -0
- package/src/filesystem/infrastructure/services/file-writer.service.ts +32 -0
- package/src/filesystem/infrastructure/utils/blob.utils.ts +20 -0
- package/src/image/infrastructure/services/ImageStorageService.ts +1 -1
- package/src/index.ts +14 -0
- package/src/media/domain/entities/CardMultimedia.types.README.md +129 -0
- package/src/media/domain/entities/CardMultimedia.types.ts +105 -0
- package/src/media/domain/entities/Media.README.md +80 -0
- package/src/media/domain/entities/Media.ts +139 -0
- package/src/media/domain/entities/MultimediaFlashcardTypes.README.md +144 -0
- package/src/media/domain/entities/MultimediaFlashcardTypes.ts +105 -0
- package/src/media/domain/utils/MediaUtils.README.md +178 -0
- package/src/media/domain/utils/MediaUtils.ts +82 -0
- package/src/media/index.ts +70 -0
- package/src/media/index.ts.README.md +191 -0
- package/src/media/infrastructure/services/CardMediaGenerationService.README.md +99 -0
- package/src/media/infrastructure/services/CardMediaGenerationService.ts +101 -0
- package/src/media/infrastructure/services/CardMediaOptimizerService.README.md +167 -0
- package/src/media/infrastructure/services/CardMediaOptimizerService.ts +36 -0
- package/src/media/infrastructure/services/CardMediaUploadService.README.md +123 -0
- package/src/media/infrastructure/services/CardMediaUploadService.ts +67 -0
- package/src/media/infrastructure/services/CardMediaValidationService.README.md +134 -0
- package/src/media/infrastructure/services/CardMediaValidationService.ts +81 -0
- package/src/media/infrastructure/services/CardMultimediaService.README.md +176 -0
- package/src/media/infrastructure/services/CardMultimediaService.ts +97 -0
- package/src/media/infrastructure/services/MediaGenerationService.README.md +142 -0
- package/src/media/infrastructure/services/MediaGenerationService.ts +80 -0
- package/src/media/infrastructure/services/MediaOptimizerService.README.md +145 -0
- package/src/media/infrastructure/services/MediaOptimizerService.ts +32 -0
- package/src/media/infrastructure/services/MediaPickerService.README.md +106 -0
- package/src/media/infrastructure/services/MediaPickerService.ts +173 -0
- package/src/media/infrastructure/services/MediaSaveService.README.md +120 -0
- package/src/media/infrastructure/services/MediaSaveService.ts +154 -0
- package/src/media/infrastructure/services/MediaUploadService.README.md +135 -0
- package/src/media/infrastructure/services/MediaUploadService.ts +62 -0
- package/src/media/infrastructure/services/MediaValidationService.README.md +135 -0
- package/src/media/infrastructure/services/MediaValidationService.ts +61 -0
- package/src/media/infrastructure/services/MultimediaFlashcardService.README.md +142 -0
- package/src/media/infrastructure/services/MultimediaFlashcardService.ts +95 -0
- package/src/media/infrastructure/utils/mediaHelpers.README.md +96 -0
- package/src/media/infrastructure/utils/mediaHelpers.ts +82 -0
- package/src/media/infrastructure/utils/mediaPickerMappers.README.md +129 -0
- package/src/media/infrastructure/utils/mediaPickerMappers.ts +76 -0
- package/src/media/presentation/hooks/card-multimedia.types.README.md +177 -0
- package/src/media/presentation/hooks/card-multimedia.types.ts +51 -0
- package/src/media/presentation/hooks/multimedia.types.README.md +201 -0
- package/src/media/presentation/hooks/multimedia.types.ts +51 -0
- package/src/media/presentation/hooks/useCardMediaGeneration.README.md +164 -0
- package/src/media/presentation/hooks/useCardMediaGeneration.ts +124 -0
- package/src/media/presentation/hooks/useCardMediaUpload.README.md +153 -0
- package/src/media/presentation/hooks/useCardMediaUpload.ts +86 -0
- package/src/media/presentation/hooks/useCardMediaValidation.README.md +176 -0
- package/src/media/presentation/hooks/useCardMediaValidation.ts +101 -0
- package/src/media/presentation/hooks/useCardMultimediaFlashcard.README.md +158 -0
- package/src/media/presentation/hooks/useCardMultimediaFlashcard.ts +104 -0
- package/src/media/presentation/hooks/useMedia.README.md +94 -0
- package/src/media/presentation/hooks/useMedia.ts +186 -0
- package/src/media/presentation/hooks/useMediaGeneration.README.md +118 -0
- package/src/media/presentation/hooks/useMediaGeneration.ts +101 -0
- package/src/media/presentation/hooks/useMediaUpload.README.md +108 -0
- package/src/media/presentation/hooks/useMediaUpload.ts +86 -0
- package/src/media/presentation/hooks/useMediaValidation.README.md +134 -0
- package/src/media/presentation/hooks/useMediaValidation.ts +93 -0
- package/src/media/presentation/hooks/useMultimediaFlashcard.README.md +141 -0
- package/src/media/presentation/hooks/useMultimediaFlashcard.ts +103 -0
- package/src/molecules/alerts/AlertStore.ts +1 -1
- package/src/molecules/calendar/infrastructure/storage/EventActions.ts +1 -1
- package/src/molecules/calendar/infrastructure/stores/storageAdapter.ts +1 -1
- package/src/offline/infrastructure/storage/OfflineStore.ts +1 -1
- package/src/onboarding/infrastructure/storage/OnboardingStore.ts +2 -2
- package/src/onboarding/infrastructure/storage/__tests__/OnboardingStore.test.ts +1 -1
- package/src/onboarding/infrastructure/storage/actions/answerActions.ts +1 -1
- package/src/onboarding/infrastructure/storage/actions/storageHelpers.ts +1 -1
- package/src/storage/README.md +185 -0
- package/src/storage/__tests__/integration.test.ts +391 -0
- package/src/storage/__tests__/mocks/asyncStorage.mock.ts +52 -0
- package/src/storage/__tests__/performance.test.tsx +352 -0
- package/src/storage/__tests__/setup.ts +63 -0
- package/src/storage/application/README.md +158 -0
- package/src/storage/application/ports/IStorageRepository.ts +61 -0
- package/src/storage/application/ports/README.md +127 -0
- package/src/storage/cache/README.md +154 -0
- package/src/storage/cache/__tests__/PerformanceAndMemory.test.ts +387 -0
- package/src/storage/cache/__tests__/setup.ts +19 -0
- package/src/storage/cache/domain/Cache.ts +146 -0
- package/src/storage/cache/domain/CacheManager.md +83 -0
- package/src/storage/cache/domain/CacheManager.ts +48 -0
- package/src/storage/cache/domain/CacheStatsTracker.md +169 -0
- package/src/storage/cache/domain/CacheStatsTracker.ts +49 -0
- package/src/storage/cache/domain/CachedValue.md +97 -0
- package/src/storage/cache/domain/ErrorHandler.md +99 -0
- package/src/storage/cache/domain/ErrorHandler.ts +42 -0
- package/src/storage/cache/domain/PatternMatcher.md +122 -0
- package/src/storage/cache/domain/PatternMatcher.ts +30 -0
- package/src/storage/cache/domain/README.md +118 -0
- package/src/storage/cache/domain/__tests__/Cache.test.ts +293 -0
- package/src/storage/cache/domain/__tests__/CacheManager.test.ts +276 -0
- package/src/storage/cache/domain/__tests__/ErrorHandler.test.ts +303 -0
- package/src/storage/cache/domain/__tests__/PatternMatcher.test.ts +261 -0
- package/src/storage/cache/domain/strategies/EvictionStrategy.ts +9 -0
- package/src/storage/cache/domain/strategies/FIFOStrategy.ts +12 -0
- package/src/storage/cache/domain/strategies/LFUStrategy.ts +22 -0
- package/src/storage/cache/domain/strategies/LRUStrategy.ts +22 -0
- package/src/storage/cache/domain/strategies/README.md +117 -0
- package/src/storage/cache/domain/strategies/TTLStrategy.ts +23 -0
- package/src/storage/cache/domain/strategies/__tests__/EvictionStrategies.test.ts +293 -0
- package/src/storage/cache/domain/types/Cache.ts +28 -0
- package/src/storage/cache/domain/types/README.md +107 -0
- package/src/storage/cache/index.ts +28 -0
- package/src/storage/cache/infrastructure/README.md +126 -0
- package/src/storage/cache/infrastructure/TTLCache.ts +103 -0
- package/src/storage/cache/infrastructure/__tests__/TTLCache.test.ts +303 -0
- package/src/storage/cache/presentation/README.md +123 -0
- package/src/storage/cache/presentation/__tests__/ReactHooks.test.ts +514 -0
- package/src/storage/cache/presentation/useCache.ts +76 -0
- package/src/storage/cache/presentation/useCachedValue.ts +88 -0
- package/src/storage/cache/types.d.ts +3 -0
- package/src/storage/domain/README.md +128 -0
- package/src/storage/domain/constants/CacheDefaults.ts +64 -0
- package/src/storage/domain/constants/README.md +105 -0
- package/src/storage/domain/entities/CachedValue.ts +86 -0
- package/src/storage/domain/entities/README.md +109 -0
- package/src/storage/domain/entities/StorageResult.ts +75 -0
- package/src/storage/domain/entities/__tests__/CachedValue.test.ts +149 -0
- package/src/storage/domain/entities/__tests__/StorageResult.test.ts +122 -0
- package/src/storage/domain/errors/README.md +126 -0
- package/src/storage/domain/errors/StorageError.ts +81 -0
- package/src/storage/domain/errors/__tests__/StorageError.test.ts +127 -0
- package/src/storage/domain/factories/README.md +138 -0
- package/src/storage/domain/factories/StoreFactory.ts +59 -0
- package/src/storage/domain/types/README.md +522 -0
- package/src/storage/domain/types/Store.ts +44 -0
- package/src/storage/domain/utils/CacheKeyGenerator.ts +66 -0
- package/src/storage/domain/utils/README.md +127 -0
- package/src/storage/domain/utils/__tests__/devUtils.test.ts +97 -0
- package/src/storage/domain/utils/devUtils.ts +37 -0
- package/src/storage/domain/value-objects/README.md +120 -0
- package/src/storage/domain/value-objects/StorageKey.ts +60 -0
- package/src/storage/index.ts +175 -0
- package/src/storage/infrastructure/README.md +165 -0
- package/src/storage/infrastructure/adapters/README.md +175 -0
- package/src/storage/infrastructure/adapters/StorageService.md +103 -0
- package/src/storage/infrastructure/adapters/StorageService.ts +49 -0
- package/src/storage/infrastructure/repositories/AsyncStorageRepository.ts +98 -0
- package/src/storage/infrastructure/repositories/BaseStorageOperations.ts +100 -0
- package/src/storage/infrastructure/repositories/BatchStorageOperations.ts +42 -0
- package/src/storage/infrastructure/repositories/README.md +121 -0
- package/src/storage/infrastructure/repositories/StringStorageOperations.ts +44 -0
- package/src/storage/infrastructure/repositories/__tests__/AsyncStorageRepository.test.ts +170 -0
- package/src/storage/infrastructure/repositories/__tests__/BaseStorageOperations.test.ts +201 -0
- package/src/storage/presentation/README.md +181 -0
- package/src/storage/presentation/hooks/CacheStorageOperations.ts +94 -0
- package/src/storage/presentation/hooks/README.md +128 -0
- package/src/storage/presentation/hooks/__tests__/usePersistentCache.test.ts +405 -0
- package/src/storage/presentation/hooks/__tests__/useStorage.test.ts +247 -0
- package/src/storage/presentation/hooks/__tests__/useStorageState.test.ts +293 -0
- package/src/storage/presentation/hooks/useCacheState.ts +53 -0
- package/src/storage/presentation/hooks/usePersistentCache.ts +154 -0
- package/src/storage/presentation/hooks/useStorage.ts +102 -0
- package/src/storage/presentation/hooks/useStorageState.ts +71 -0
- package/src/storage/presentation/hooks/useStore.ts +15 -0
- package/src/storage/types/README.md +103 -0
- package/src/theme/infrastructure/globalThemeStore.ts +1 -1
- package/src/theme/infrastructure/storage/ThemeStorage.ts +1 -1
- package/src/theme/infrastructure/stores/themeStore.ts +1 -1
- package/src/utilities/sharing/infrastructure/services/SharingService.ts +1 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Card Media Generation Hook
|
|
3
|
+
* Hook for generating card media with AI
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from "react";
|
|
7
|
+
import type { UseCardMediaGenerationResult } from "./card-multimedia.types";
|
|
8
|
+
import type {
|
|
9
|
+
CardMediaAttachment,
|
|
10
|
+
CardMediaGenerationRequest,
|
|
11
|
+
CardMediaGenerationResult,
|
|
12
|
+
} from "../../domain/entities/CardMultimedia.types";
|
|
13
|
+
|
|
14
|
+
export const useCardMediaGeneration = (): UseCardMediaGenerationResult => {
|
|
15
|
+
const [isGenerating, setIsGenerating] = React.useState(false);
|
|
16
|
+
const [generationResult, setGenerationResult] =
|
|
17
|
+
React.useState<CardMediaGenerationResult | null>(null);
|
|
18
|
+
const [error, setError] = React.useState<string | null>(null);
|
|
19
|
+
|
|
20
|
+
const generateMedia = React.useCallback(
|
|
21
|
+
async (
|
|
22
|
+
request: CardMediaGenerationRequest,
|
|
23
|
+
): Promise<CardMediaGenerationResult> => {
|
|
24
|
+
try {
|
|
25
|
+
setIsGenerating(true);
|
|
26
|
+
setError(null);
|
|
27
|
+
|
|
28
|
+
// Simulate generation
|
|
29
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
30
|
+
|
|
31
|
+
const attachments: CardMediaAttachment[] = [];
|
|
32
|
+
|
|
33
|
+
switch (request.type) {
|
|
34
|
+
case "text_to_image":
|
|
35
|
+
for (let i = 0; i < (request.options.maxResults || 1); i++) {
|
|
36
|
+
attachments.push({
|
|
37
|
+
id: `ai_img_${Date.now()}_${i}`,
|
|
38
|
+
type: "image",
|
|
39
|
+
position: "both",
|
|
40
|
+
url: `https://picsum.photos/400/300?random=${Date.now() + i}`,
|
|
41
|
+
filename: `ai_generated_${i}.jpg`,
|
|
42
|
+
fileSize: 150000, // 150KB
|
|
43
|
+
mimeType: "image/jpeg",
|
|
44
|
+
isDownloaded: false,
|
|
45
|
+
createdAt: new Date().toISOString(),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
|
|
50
|
+
case "text_to_audio":
|
|
51
|
+
attachments.push({
|
|
52
|
+
id: `ai_audio_${Date.now()}`,
|
|
53
|
+
type: "audio",
|
|
54
|
+
position: "back",
|
|
55
|
+
url: `https://example.com/audio_${Date.now()}.mp3`,
|
|
56
|
+
filename: `ai_generated_${Date.now()}.mp3`,
|
|
57
|
+
fileSize: 80000, // 80KB
|
|
58
|
+
mimeType: "audio/mp3",
|
|
59
|
+
duration: 10, // 10 seconds
|
|
60
|
+
isDownloaded: false,
|
|
61
|
+
createdAt: new Date().toISOString(),
|
|
62
|
+
});
|
|
63
|
+
break;
|
|
64
|
+
|
|
65
|
+
case "image_search":
|
|
66
|
+
for (let i = 0; i < (request.options.maxResults || 5); i++) {
|
|
67
|
+
attachments.push({
|
|
68
|
+
id: `search_img_${Date.now()}_${i}`,
|
|
69
|
+
type: "image",
|
|
70
|
+
position: "both",
|
|
71
|
+
url: `https://picsum.photos/400/300?random=${Date.now() + i}`,
|
|
72
|
+
filename: `search_result_${i}.jpg`,
|
|
73
|
+
fileSize: 120000, // 120KB
|
|
74
|
+
mimeType: "image/jpeg",
|
|
75
|
+
isDownloaded: false,
|
|
76
|
+
createdAt: new Date().toISOString(),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const result: CardMediaGenerationResult = {
|
|
83
|
+
success: true,
|
|
84
|
+
attachments,
|
|
85
|
+
creditsUsed:
|
|
86
|
+
request.type === "text_to_image"
|
|
87
|
+
? 5
|
|
88
|
+
: request.type === "text_to_audio"
|
|
89
|
+
? 3
|
|
90
|
+
: 2,
|
|
91
|
+
processingTime: 3000,
|
|
92
|
+
requestId: `req_${Date.now()}`,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
setGenerationResult(result);
|
|
96
|
+
return result;
|
|
97
|
+
} catch (err) {
|
|
98
|
+
const errorMessage =
|
|
99
|
+
err instanceof Error ? err.message : "Generation failed";
|
|
100
|
+
setError(errorMessage);
|
|
101
|
+
setIsGenerating(false);
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
success: false,
|
|
105
|
+
attachments: [],
|
|
106
|
+
creditsUsed: 0,
|
|
107
|
+
processingTime: 0,
|
|
108
|
+
error: errorMessage,
|
|
109
|
+
requestId: "",
|
|
110
|
+
};
|
|
111
|
+
} finally {
|
|
112
|
+
setIsGenerating(false);
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
[],
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
generateMedia,
|
|
120
|
+
isGenerating,
|
|
121
|
+
generationResult,
|
|
122
|
+
error,
|
|
123
|
+
};
|
|
124
|
+
};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# useCardMediaUpload
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
Card-specific React hook for uploading flashcard media files to server with progress tracking and compression support.
|
|
5
|
+
|
|
6
|
+
## File Location
|
|
7
|
+
`src/presentation/hooks/useCardMediaUpload.ts`
|
|
8
|
+
|
|
9
|
+
## Strategy
|
|
10
|
+
- Provide card-specific media upload interface
|
|
11
|
+
- Support compression options for optimization
|
|
12
|
+
- Track upload progress with percentage and status
|
|
13
|
+
- Return CardMediaAttachment with position property
|
|
14
|
+
- Handle upload errors gracefully
|
|
15
|
+
- Generate thumbnails for visual media
|
|
16
|
+
- Support various media types for cards
|
|
17
|
+
|
|
18
|
+
## Forbidden
|
|
19
|
+
- **DO NOT** start upload while previous is in progress
|
|
20
|
+
- **DO NOT** ignore compression options
|
|
21
|
+
- **DO NOT** upload without validation (use useCardMediaValidation)
|
|
22
|
+
- **DO NOT** mock upload in production without backend integration
|
|
23
|
+
- **DO NOT** modify file during upload (compress before)
|
|
24
|
+
- **DO NOT** assume upload will succeed
|
|
25
|
+
- **DO NOT** use hardcoded API endpoints
|
|
26
|
+
- **DO NOT** bypass progress tracking
|
|
27
|
+
- **DO NOT** store upload results permanently in state
|
|
28
|
+
- **DO NOT** use incorrect ID prefixes (must use card_media_)
|
|
29
|
+
|
|
30
|
+
## Rules
|
|
31
|
+
1. Always validate before uploading (use useCardMediaValidation)
|
|
32
|
+
2. Compression quality must be in 0-1 range
|
|
33
|
+
3. Dimensions must be in pixels
|
|
34
|
+
4. Progress updates every 10% or on status change
|
|
35
|
+
5. Clear upload state on error or completion
|
|
36
|
+
6. Return CardMediaAttachment with position property
|
|
37
|
+
7. Generate thumbnail URL automatically
|
|
38
|
+
8. Calculate duration for audio/video
|
|
39
|
+
9. Update progress status: uploading -> completed/error
|
|
40
|
+
10. Include unique fileId in progress tracking
|
|
41
|
+
|
|
42
|
+
## AI Agent Guidelines
|
|
43
|
+
|
|
44
|
+
When working with useCardMediaUpload hook:
|
|
45
|
+
|
|
46
|
+
1. **Type Correctness**: Returns CardMediaAttachment (not MediaAttachment)
|
|
47
|
+
2. **Position Property**: Uploaded media includes position field
|
|
48
|
+
3. **Pre-upload Validation**: Always use useCardMediaValidation first
|
|
49
|
+
4. **Progress Tracking**: Monitor uploadProgress for real-time updates
|
|
50
|
+
5. **Compression**: Apply appropriate compression settings
|
|
51
|
+
|
|
52
|
+
### Upload Workflow
|
|
53
|
+
|
|
54
|
+
1. Validate file with useCardMediaValidation
|
|
55
|
+
2. Select compression options based on type and size
|
|
56
|
+
3. Call uploadMedia with file and options
|
|
57
|
+
4. Monitor uploadProgress state
|
|
58
|
+
5. Handle completion (success or error)
|
|
59
|
+
6. Process returned CardMediaAttachment
|
|
60
|
+
|
|
61
|
+
### CardMediaAttachment Structure
|
|
62
|
+
|
|
63
|
+
Returned object includes:
|
|
64
|
+
- id: Unique ID with card_media_ prefix
|
|
65
|
+
- type: CardMediaType (IMAGE, VIDEO, AUDIO)
|
|
66
|
+
- position: CardMediaPosition (defaults to 'both')
|
|
67
|
+
- url: Uploaded file URL
|
|
68
|
+
- filename: Original filename
|
|
69
|
+
- fileSize: Size in bytes
|
|
70
|
+
- mimeType: MIME type string
|
|
71
|
+
- duration: Audio/video duration
|
|
72
|
+
- thumbnailUrl: Thumbnail for visual media
|
|
73
|
+
- caption: Optional caption text
|
|
74
|
+
- isDownloaded: Download status
|
|
75
|
+
- createdAt: ISO timestamp
|
|
76
|
+
|
|
77
|
+
### Compression Guidelines
|
|
78
|
+
|
|
79
|
+
**High Quality** (quality: 0.9, maxWidth: 4096)
|
|
80
|
+
- Use for detailed card images
|
|
81
|
+
- Larger file size, best quality
|
|
82
|
+
|
|
83
|
+
**Medium Quality** (quality: 0.7, maxWidth: 1920) - RECOMMENDED
|
|
84
|
+
- Balanced quality and size
|
|
85
|
+
- Good for most card media
|
|
86
|
+
|
|
87
|
+
**Low Quality** (quality: 0.5, maxWidth: 1280)
|
|
88
|
+
- Use for card thumbnails
|
|
89
|
+
- Smallest size, reduced quality
|
|
90
|
+
|
|
91
|
+
### Upload Progress States
|
|
92
|
+
|
|
93
|
+
- **uploading**: Upload in progress (0-99%)
|
|
94
|
+
- **completed**: Upload finished successfully (100%)
|
|
95
|
+
- **error**: Upload failed with error message
|
|
96
|
+
|
|
97
|
+
### CardMediaUploadProgress
|
|
98
|
+
|
|
99
|
+
Progress object includes:
|
|
100
|
+
- fileId: Unique file identifier
|
|
101
|
+
- progress: Percentage (0-100)
|
|
102
|
+
- status: Current state (uploading/completed/error)
|
|
103
|
+
- url: Final URL when completed
|
|
104
|
+
|
|
105
|
+
### Integration with Card Creation
|
|
106
|
+
|
|
107
|
+
Typical workflow:
|
|
108
|
+
1. Select or generate media
|
|
109
|
+
2. Validate with useCardMediaValidation
|
|
110
|
+
3. Upload with useCardMediaUpload
|
|
111
|
+
4. Receive CardMediaAttachment with position
|
|
112
|
+
5. Add to card media array
|
|
113
|
+
6. Create card with useCardMultimediaFlashcard
|
|
114
|
+
|
|
115
|
+
### Position Assignment
|
|
116
|
+
|
|
117
|
+
Uploaded media gets position property:
|
|
118
|
+
- Default: 'both' (shown on both sides)
|
|
119
|
+
- Can be overridden: 'front' or 'back'
|
|
120
|
+
- Used to control media display on card sides
|
|
121
|
+
|
|
122
|
+
### Multiple File Upload
|
|
123
|
+
|
|
124
|
+
For multiple media files:
|
|
125
|
+
1. Upload files sequentially or in parallel
|
|
126
|
+
2. Collect CardMediaAttachment objects
|
|
127
|
+
3. Assign positions appropriately
|
|
128
|
+
4. Add to card media array
|
|
129
|
+
5. Track individual upload progress
|
|
130
|
+
|
|
131
|
+
### Integration Requirements
|
|
132
|
+
|
|
133
|
+
- Configure API endpoint for card media upload
|
|
134
|
+
- Implement authentication for uploads
|
|
135
|
+
- Handle file size limits
|
|
136
|
+
- Support retry logic for failures
|
|
137
|
+
- Generate thumbnails automatically
|
|
138
|
+
- Calculate media duration for audio/video
|
|
139
|
+
|
|
140
|
+
### Error Handling
|
|
141
|
+
|
|
142
|
+
Common error scenarios:
|
|
143
|
+
- File too large: Validate before upload
|
|
144
|
+
- Unsupported type: Check MIME type
|
|
145
|
+
- Network timeout: Implement retry with backoff
|
|
146
|
+
- Server error: Display user-friendly message
|
|
147
|
+
- Authentication failure: Check token validity
|
|
148
|
+
|
|
149
|
+
## Dependencies
|
|
150
|
+
|
|
151
|
+
- CardMediaUploadService (infrastructure layer)
|
|
152
|
+
- Domain types: CardMediaAttachment, CardMediaCompressionOptions, CardMediaUploadProgress
|
|
153
|
+
- useCardMediaValidation (for pre-upload validation)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Card Media Upload Hook
|
|
3
|
+
* Hook for uploading card media files
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from "react";
|
|
7
|
+
import {
|
|
8
|
+
generateThumbnail,
|
|
9
|
+
getCardMediaType,
|
|
10
|
+
getMediaDuration,
|
|
11
|
+
} from "../../infrastructure/utils/mediaHelpers";
|
|
12
|
+
import type { UseCardMediaUploadResult } from "./card-multimedia.types";
|
|
13
|
+
import type {
|
|
14
|
+
CardMediaAttachment,
|
|
15
|
+
CardMediaCompressionOptions,
|
|
16
|
+
CardMediaUploadProgress,
|
|
17
|
+
} from "../../domain/entities/CardMultimedia.types";
|
|
18
|
+
|
|
19
|
+
export const useCardMediaUpload = (): UseCardMediaUploadResult => {
|
|
20
|
+
const [isUploading, setIsUploading] = React.useState(false);
|
|
21
|
+
const [uploadProgress, setUploadProgress] =
|
|
22
|
+
React.useState<CardMediaUploadProgress | null>(null);
|
|
23
|
+
const [error, setError] = React.useState<string | null>(null);
|
|
24
|
+
|
|
25
|
+
const uploadMedia = React.useCallback(
|
|
26
|
+
async (file: any, options?: CardMediaCompressionOptions) => {
|
|
27
|
+
try {
|
|
28
|
+
setIsUploading(true);
|
|
29
|
+
setError(null);
|
|
30
|
+
|
|
31
|
+
// Simulate upload progress
|
|
32
|
+
setUploadProgress({
|
|
33
|
+
fileId: `upload_${Date.now()}`,
|
|
34
|
+
progress: 0,
|
|
35
|
+
status: "uploading",
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Simulate progress updates
|
|
39
|
+
for (let i = 1; i <= 100; i += 10) {
|
|
40
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
41
|
+
setUploadProgress((prev) => (prev ? { ...prev, progress: i } : null));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const attachment: CardMediaAttachment = {
|
|
45
|
+
id: `card_media_${Date.now()}`,
|
|
46
|
+
type: getCardMediaType(file.type),
|
|
47
|
+
position: "both",
|
|
48
|
+
url: `https://storage.example.com/media/${Date.now()}_${file.name}`,
|
|
49
|
+
filename: file.name,
|
|
50
|
+
fileSize: file.size || 100000,
|
|
51
|
+
mimeType: file.type,
|
|
52
|
+
duration: await getMediaDuration(file),
|
|
53
|
+
thumbnailUrl: generateThumbnail(file),
|
|
54
|
+
caption: "",
|
|
55
|
+
isDownloaded: true,
|
|
56
|
+
createdAt: new Date().toISOString(),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
setUploadProgress({
|
|
60
|
+
fileId: `upload_${Date.now()}`,
|
|
61
|
+
progress: 100,
|
|
62
|
+
status: "completed",
|
|
63
|
+
url: attachment.url,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return attachment;
|
|
67
|
+
} catch (err) {
|
|
68
|
+
const errorMessage =
|
|
69
|
+
err instanceof Error ? err.message : "Upload failed";
|
|
70
|
+
setError(errorMessage);
|
|
71
|
+
setIsUploading(false);
|
|
72
|
+
throw err;
|
|
73
|
+
} finally {
|
|
74
|
+
setIsUploading(false);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
[],
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
uploadMedia,
|
|
82
|
+
isUploading,
|
|
83
|
+
uploadProgress,
|
|
84
|
+
error,
|
|
85
|
+
};
|
|
86
|
+
};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# useCardMediaValidation
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
Card-specific React hook for validating flashcard media files before upload with enhanced controls for different media types.
|
|
5
|
+
|
|
6
|
+
## File Location
|
|
7
|
+
`src/presentation/hooks/useCardMediaValidation.ts`
|
|
8
|
+
|
|
9
|
+
## Strategy
|
|
10
|
+
- Provide comprehensive validation for card media files
|
|
11
|
+
- Enhanced controls for images (5 MB warning threshold)
|
|
12
|
+
- Support audio/video duration validation
|
|
13
|
+
- Provide three-tier feedback: errors, warnings, recommendations
|
|
14
|
+
- Card-specific validation rules compared to general media
|
|
15
|
+
- Enable pre-upload validation workflow for cards
|
|
16
|
+
- Return actionable feedback with media-type specific recommendations
|
|
17
|
+
|
|
18
|
+
## Forbidden
|
|
19
|
+
- **DO NOT** upload files that fail validation (have errors)
|
|
20
|
+
- **DO NOT** ignore warnings - they indicate card performance issues
|
|
21
|
+
- **DO NOT** bypass file type validation
|
|
22
|
+
- **DO NOT** use mock validation in production
|
|
23
|
+
- **DO NOT** allow files exceeding 50 MB limit
|
|
24
|
+
- **DO NOT** modify files during validation
|
|
25
|
+
- **DO NOT** store validation results permanently
|
|
26
|
+
- **DO NOT** validate empty or missing files
|
|
27
|
+
- **DO NOT** suppress errors for user convenience
|
|
28
|
+
|
|
29
|
+
## Rules
|
|
30
|
+
1. Always validate before card media upload
|
|
31
|
+
2. Files over 50 MB must be rejected
|
|
32
|
+
3. Files over 10 MB trigger warning
|
|
33
|
+
4. Images over 5 MB trigger additional warning
|
|
34
|
+
5. Unsupported MIME types must be rejected
|
|
35
|
+
6. Validate file size, type, and format
|
|
36
|
+
7. Return errors array for blocking issues
|
|
37
|
+
8. Return warnings array for performance concerns
|
|
38
|
+
9. Return recommendations array for improvements
|
|
39
|
+
10. Clear validation state on new requests
|
|
40
|
+
|
|
41
|
+
## AI Agent Guidelines
|
|
42
|
+
|
|
43
|
+
When working with useCardMediaValidation hook:
|
|
44
|
+
|
|
45
|
+
1. **Card-Specific Rules**: Use for card media (not general media)
|
|
46
|
+
2. **Enhanced Image Control**: 5 MB threshold for images (stricter than general)
|
|
47
|
+
3. **Three-Tier Feedback**: Distinguish errors, warnings, recommendations
|
|
48
|
+
4. **Duration Control**: Check audio/video duration when available
|
|
49
|
+
5. **Pre-upload Check**: Always validate before useCardMediaUpload
|
|
50
|
+
|
|
51
|
+
### Validation Levels
|
|
52
|
+
|
|
53
|
+
**Errors** (Blocking - Must fix):
|
|
54
|
+
- File size exceeds 50 MB
|
|
55
|
+
- Unsupported file type
|
|
56
|
+
- Invalid file format
|
|
57
|
+
- Missing required properties
|
|
58
|
+
|
|
59
|
+
**Warnings** (Performance - Should fix):
|
|
60
|
+
- File size over 10 MB (general warning)
|
|
61
|
+
- Image size over 5 MB (card-specific warning)
|
|
62
|
+
- Long duration audio/video
|
|
63
|
+
- Large dimensions
|
|
64
|
+
|
|
65
|
+
**Recommendations** (Improvements - Optional):
|
|
66
|
+
- Reduce file size for card performance
|
|
67
|
+
- Use recommended formats
|
|
68
|
+
- Optimize dimensions
|
|
69
|
+
- Compress for balance
|
|
70
|
+
|
|
71
|
+
### Card-Specific vs General Validation
|
|
72
|
+
|
|
73
|
+
| Feature | useMediaValidation | useCardMediaValidation |
|
|
74
|
+
|---------|-------------------|------------------------|
|
|
75
|
+
| Max file size | 50 MB | 50 MB |
|
|
76
|
+
| General warning | 10 MB | 10 MB |
|
|
77
|
+
| Image warning | None | 5 MB (extra) |
|
|
78
|
+
| Duration check | No | Yes (5 min warning) |
|
|
79
|
+
| Type support | Same | Same |
|
|
80
|
+
|
|
81
|
+
### Supported File Types
|
|
82
|
+
|
|
83
|
+
**Images:**
|
|
84
|
+
- image/jpeg
|
|
85
|
+
- image/png
|
|
86
|
+
- image/webp
|
|
87
|
+
|
|
88
|
+
**Audio:**
|
|
89
|
+
- audio/mp3
|
|
90
|
+
- audio/wav
|
|
91
|
+
- audio/m4a
|
|
92
|
+
|
|
93
|
+
**Video:**
|
|
94
|
+
- video/mp4
|
|
95
|
+
- video/mov
|
|
96
|
+
|
|
97
|
+
### Validation Workflow
|
|
98
|
+
|
|
99
|
+
1. Receive file object (name, type, size, uri)
|
|
100
|
+
2. Check file size against limits
|
|
101
|
+
3. Validate MIME type
|
|
102
|
+
4. Apply card-specific rules (5 MB image warning)
|
|
103
|
+
5. Check duration if available
|
|
104
|
+
6. Generate errors, warnings, recommendations
|
|
105
|
+
7. Return CardMediaValidation object
|
|
106
|
+
|
|
107
|
+
### CardMediaValidation Structure
|
|
108
|
+
|
|
109
|
+
Validation result includes:
|
|
110
|
+
- isValid: Boolean (true if no errors)
|
|
111
|
+
- errors: String array (blocking issues)
|
|
112
|
+
- warnings: String array (performance concerns)
|
|
113
|
+
- recommendations: String array (improvements)
|
|
114
|
+
|
|
115
|
+
### File Size Guidelines
|
|
116
|
+
|
|
117
|
+
**Images:**
|
|
118
|
+
- Optimal: Under 2 MB
|
|
119
|
+
- Card warning: 2-5 MB
|
|
120
|
+
- Extra warning: 5-10 MB
|
|
121
|
+
- Error: Over 50 MB
|
|
122
|
+
|
|
123
|
+
**Audio:**
|
|
124
|
+
- Optimal: Under 5 MB
|
|
125
|
+
- Warning: 5-10 MB
|
|
126
|
+
- Duration warning: Over 5 minutes
|
|
127
|
+
- Error: Over 50 MB
|
|
128
|
+
|
|
129
|
+
**Video:**
|
|
130
|
+
- Optimal: Under 10 MB
|
|
131
|
+
- Warning: 10-50 MB
|
|
132
|
+
- Duration warning: Over 5 minutes
|
|
133
|
+
- Error: Over 50 MB
|
|
134
|
+
|
|
135
|
+
### Media Type Special Controls
|
|
136
|
+
|
|
137
|
+
**Image Controls:**
|
|
138
|
+
- Additional 5 MB warning threshold
|
|
139
|
+
- Dimension recommendations
|
|
140
|
+
- Format recommendations (JPEG for photos, PNG for graphics)
|
|
141
|
+
|
|
142
|
+
**Audio Controls:**
|
|
143
|
+
- Duration check (warn over 5 minutes)
|
|
144
|
+
- Format recommendation (MP3 preferred)
|
|
145
|
+
- Bitrate considerations
|
|
146
|
+
|
|
147
|
+
**Video Controls:**
|
|
148
|
+
- Duration check (warn over 5 minutes)
|
|
149
|
+
- Format recommendation (MP4 preferred)
|
|
150
|
+
- Resolution recommendations
|
|
151
|
+
|
|
152
|
+
### Integration with Card Upload Flow
|
|
153
|
+
|
|
154
|
+
Typical validation-upload workflow:
|
|
155
|
+
1. Select file from picker
|
|
156
|
+
2. Call validateMedia(file) from useCardMediaValidation
|
|
157
|
+
3. Check validation.isValid
|
|
158
|
+
4. If errors: Display and block upload
|
|
159
|
+
5. If warnings: Display and get confirmation
|
|
160
|
+
6. If recommendations: Display for reference
|
|
161
|
+
7. Proceed to useCardMediaUpload if valid or confirmed
|
|
162
|
+
|
|
163
|
+
### Best Practices
|
|
164
|
+
|
|
165
|
+
1. Always validate before card media upload
|
|
166
|
+
2. Show all three feedback levels to users
|
|
167
|
+
3. Allow users to proceed with warnings
|
|
168
|
+
4. Provide actionable recommendations
|
|
169
|
+
5. Consider card performance implications
|
|
170
|
+
6. Balance quality vs. file size
|
|
171
|
+
|
|
172
|
+
## Dependencies
|
|
173
|
+
|
|
174
|
+
- CardMediaValidationService (infrastructure layer)
|
|
175
|
+
- Domain types: CardMediaValidation, file input interfaces
|
|
176
|
+
- Media constants (card-specific size limits)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Card Media Validation Hook
|
|
3
|
+
* Hook for validating card media files
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { formatFileSize } from "../../infrastructure/utils/mediaHelpers";
|
|
8
|
+
import type { UseCardMediaValidationResult } from "./card-multimedia.types";
|
|
9
|
+
import type { CardMediaValidation } from "../../domain/entities/CardMultimedia.types";
|
|
10
|
+
|
|
11
|
+
export const useCardMediaValidation = (): UseCardMediaValidationResult => {
|
|
12
|
+
const [isValidating, setIsValidating] = React.useState(false);
|
|
13
|
+
const [validation, setValidation] =
|
|
14
|
+
React.useState<CardMediaValidation | null>(null);
|
|
15
|
+
const [error, setError] = React.useState<string | null>(null);
|
|
16
|
+
|
|
17
|
+
const validateMedia = React.useCallback(
|
|
18
|
+
async (file: any): Promise<CardMediaValidation> => {
|
|
19
|
+
try {
|
|
20
|
+
setIsValidating(true);
|
|
21
|
+
setError(null);
|
|
22
|
+
|
|
23
|
+
// Simulate validation
|
|
24
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
25
|
+
|
|
26
|
+
const errors: string[] = [];
|
|
27
|
+
const warnings: string[] = [];
|
|
28
|
+
const recommendations: string[] = [];
|
|
29
|
+
|
|
30
|
+
// File size validation
|
|
31
|
+
const maxSize = 50 * 1024 * 1024; // 50MB
|
|
32
|
+
if (file.size > maxSize) {
|
|
33
|
+
errors.push(
|
|
34
|
+
`File size (${formatFileSize(file.size)}) exceeds maximum allowed size (${formatFileSize(maxSize)})`,
|
|
35
|
+
);
|
|
36
|
+
} else if (file.size > 10 * 1024 * 1024) {
|
|
37
|
+
// 10MB
|
|
38
|
+
warnings.push(`Large file size may impact performance`);
|
|
39
|
+
recommendations.push("Consider compressing file");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// File type validation
|
|
43
|
+
const supportedTypes = [
|
|
44
|
+
"image/jpeg",
|
|
45
|
+
"image/png",
|
|
46
|
+
"image/webp",
|
|
47
|
+
"audio/mp3",
|
|
48
|
+
"audio/wav",
|
|
49
|
+
"audio/m4a",
|
|
50
|
+
"video/mp4",
|
|
51
|
+
"video/mov",
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
if (!supportedTypes.includes(file.type)) {
|
|
55
|
+
errors.push(`Unsupported file type: ${file.type}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Media-specific validations
|
|
59
|
+
if (file.type.startsWith("image/")) {
|
|
60
|
+
if (file.size > 5 * 1024 * 1024) {
|
|
61
|
+
// 5MB for images
|
|
62
|
+
warnings.push("Very large image may cause performance issues");
|
|
63
|
+
recommendations.push("Consider resizing image to under 5MB");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const result: CardMediaValidation = {
|
|
68
|
+
isValid: errors.length === 0,
|
|
69
|
+
errors,
|
|
70
|
+
warnings,
|
|
71
|
+
recommendations,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
setValidation(result);
|
|
75
|
+
return result;
|
|
76
|
+
} catch (err) {
|
|
77
|
+
const errorMessage =
|
|
78
|
+
err instanceof Error ? err.message : "Validation failed";
|
|
79
|
+
setError(errorMessage);
|
|
80
|
+
setIsValidating(false);
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
isValid: false,
|
|
84
|
+
errors: [errorMessage],
|
|
85
|
+
warnings: [],
|
|
86
|
+
recommendations: [],
|
|
87
|
+
};
|
|
88
|
+
} finally {
|
|
89
|
+
setIsValidating(false);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
[],
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
validateMedia,
|
|
97
|
+
isValidating,
|
|
98
|
+
validation,
|
|
99
|
+
error,
|
|
100
|
+
};
|
|
101
|
+
};
|