@umituz/react-native-design-system 4.23.101 → 4.23.103

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-design-system",
3
- "version": "4.23.101",
3
+ "version": "4.23.103",
4
4
  "description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive, safe area, exception, infinite scroll, UUID, image, timezone, offline, onboarding, and loading utilities",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -1,16 +1,14 @@
1
1
  /**
2
- * @umituz/react-native-media - Enhanced Public API
2
+ * @umituz/react-native-media - Public API
3
3
  *
4
4
  * Media picking capabilities for React Native apps
5
- * Includes multimedia flashcard support
6
5
  *
7
6
  * Usage:
8
7
  * import {
9
8
  * useMedia,
10
- * useMultimediaFlashcard,
11
- * MultimediaFlashcardService,
12
- * type MediaAttachment,
13
- * type MultimediaFlashcard,
9
+ * MediaPickerService,
10
+ * type MediaAsset,
11
+ * type MediaPickerResult,
14
12
  * } from '@umituz/react-native-media';
15
13
  */
16
14
 
@@ -90,30 +88,3 @@ export {
90
88
  saveVideoToGallery,
91
89
  type SaveToGalleryResult,
92
90
  } from "./infrastructure/utils/file-media-utils";
93
-
94
- // Media Attachment Types (Clean, no aliases)
95
- export type {
96
- MediaAttachmentType,
97
- MediaPosition,
98
- MediaAttachment,
99
- MultimediaFlashcard,
100
- MediaGenerationRequest,
101
- MediaGenerationResult,
102
- MediaUploadProgress,
103
- MediaCompressionOptions,
104
- MediaValidation,
105
- MediaFile,
106
- CreateMultimediaCardData,
107
- } from "./domain/entities/MediaAttachments";
108
-
109
- // Media Hooks
110
- export { useMediaUpload } from "./presentation/hooks/useMediaUpload";
111
- export { useMediaGeneration } from "./presentation/hooks/useMediaGeneration";
112
- export { useMediaValidation } from "./presentation/hooks/useMediaValidation";
113
- export { useMultimediaFlashcard } from "./presentation/hooks/useMultimediaFlashcard";
114
- export type {
115
- UseMediaUploadResult,
116
- UseMediaGenerationResult,
117
- UseMediaValidationResult,
118
- UseMultimediaFlashcardResult,
119
- } from "./presentation/hooks/multimedia.types";
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import * as ImagePicker from "expo-image-picker";
8
- import { MediaLibraryPermission } from "../../domain/entities/MediaAttachments";
8
+ import { MediaLibraryPermission } from "../../domain/entities/Media";
9
9
  import { mapPermissionStatus } from "./mediaPickerMappers";
10
10
 
11
11
  /**
@@ -1,14 +1,28 @@
1
- import type { MediaAttachment } from "../../domain/entities/MediaAttachments";
2
-
3
- // CardMediaAttachment is an alias of MediaAttachment
4
- type CardMediaAttachment = MediaAttachment;
1
+ /**
2
+ * Media Collection Utilities
3
+ * Generic utilities for working with media collections
4
+ */
5
5
 
6
6
  type MediaType = "image" | "audio" | "video";
7
7
 
8
8
  const FILE_SIZE_UNITS = ["Bytes", "KB", "MB", "GB"] as const;
9
9
 
10
+ /**
11
+ * Interface for media items with type property
12
+ */
13
+ interface MediaWithType {
14
+ type: MediaType;
15
+ }
16
+
17
+ /**
18
+ * Interface for media items with file size
19
+ */
20
+ interface MediaWithSize {
21
+ fileSize: number;
22
+ }
23
+
10
24
  export function extractMediaTypes(
11
- media: readonly (CardMediaAttachment | MediaAttachment)[]
25
+ media: readonly MediaWithType[]
12
26
  ): MediaType[] {
13
27
  const types = new Set<MediaType>();
14
28
  media.forEach((m) => types.add(m.type));
@@ -16,7 +30,7 @@ export function extractMediaTypes(
16
30
  }
17
31
 
18
32
  export function calculateTotalSize(
19
- media: readonly (CardMediaAttachment | MediaAttachment)[]
33
+ media: readonly MediaWithSize[]
20
34
  ): number {
21
35
  return media.reduce((total, m) => total + m.fileSize, 0);
22
36
  }
@@ -9,7 +9,7 @@ import {
9
9
  MediaType,
10
10
  type MediaAsset,
11
11
  type MediaPickerResult,
12
- } from "../../domain/entities/MediaAttachments";
12
+ } from "../../domain/entities/Media";
13
13
 
14
14
  /**
15
15
  * Map expo-image-picker permission status to MediaLibraryPermission
@@ -12,8 +12,8 @@ import type {
12
12
  MediaPickerOptions,
13
13
  MediaPickerResult,
14
14
  CameraOptions,
15
- } from "../../domain/entities/MediaAttachments";
16
- import { MediaLibraryPermission } from "../../domain/entities/MediaAttachments";
15
+ } from "../../domain/entities/Media";
16
+ import { MediaLibraryPermission } from "../../domain/entities/Media";
17
17
 
18
18
  /**
19
19
  * useMedia hook for complete media workflow
@@ -37,7 +37,7 @@ export class BaseStorageOperations {
37
37
  return failure(new StorageDeserializationError(key, parseError), defaultValue);
38
38
  }
39
39
  } catch (_error) {
40
- return failure(new StorageReadError(key, error), defaultValue);
40
+ return failure(new StorageReadError(key, _error), defaultValue);
41
41
  }
42
42
  }
43
43
 
@@ -56,7 +56,7 @@ export class BaseStorageOperations {
56
56
  await AsyncStorage.setItem(key, serialized);
57
57
  return success(value);
58
58
  } catch (_error) {
59
- return failure(new StorageWriteError(key, error));
59
+ return failure(new StorageWriteError(key, _error));
60
60
  }
61
61
  }
62
62
 
@@ -68,7 +68,7 @@ export class BaseStorageOperations {
68
68
  await AsyncStorage.removeItem(key);
69
69
  return success(undefined);
70
70
  } catch (_error) {
71
- return failure(new StorageDeleteError(key, error));
71
+ return failure(new StorageDeleteError(key, _error));
72
72
  }
73
73
  }
74
74
 
@@ -92,7 +92,7 @@ export class BaseStorageOperations {
92
92
  await AsyncStorage.clear();
93
93
  return success(undefined);
94
94
  } catch (_error) {
95
- return failure(new StorageDeleteError('ALL_KEYS', error));
95
+ return failure(new StorageDeleteError('ALL_KEYS', _error));
96
96
  }
97
97
  }
98
98
  }
@@ -1,101 +0,0 @@
1
- /**
2
- * Media Attachments Types
3
- * Types for media attachments in flashcards and content
4
- */
5
-
6
- export type MediaAttachmentType = "image" | "audio" | "video";
7
- export type MediaPosition = "front" | "back" | "both";
8
-
9
- export interface MediaAttachment {
10
- id: string;
11
- type: MediaAttachmentType;
12
- position: MediaPosition;
13
- url: string;
14
- localPath?: string;
15
- filename: string;
16
- fileSize: number;
17
- mimeType: string;
18
- duration?: number;
19
- thumbnailUrl?: string;
20
- caption?: string;
21
- isDownloaded: boolean;
22
- createdAt: string;
23
- }
24
-
25
- export interface MultimediaFlashcard {
26
- id: string;
27
- front: string;
28
- back: string;
29
- difficulty: "easy" | "medium" | "hard";
30
- tags: string[];
31
- createdAt?: string;
32
- updatedAt?: string;
33
- media: MediaAttachment[];
34
- hasMedia: boolean;
35
- mediaType: MediaAttachmentType[];
36
- isDownloaded: boolean;
37
- estimatedSize: number;
38
- }
39
-
40
- export interface MediaGenerationRequest {
41
- type: "text_to_image" | "text_to_audio" | "image_search";
42
- input: {
43
- text?: string;
44
- prompt?: string;
45
- language?: string;
46
- voice?: "male" | "female" | "neutral";
47
- style?: "realistic" | "cartoon" | "artistic";
48
- };
49
- options: {
50
- maxResults?: number;
51
- quality?: "low" | "medium" | "high";
52
- format?: "jpeg" | "png" | "mp3" | "wav";
53
- };
54
- }
55
-
56
- export interface MediaGenerationResult {
57
- success: boolean;
58
- attachments: MediaAttachment[];
59
- creditsUsed: number;
60
- processingTime: number;
61
- error?: string;
62
- requestId: string;
63
- }
64
-
65
- export interface MediaUploadProgress {
66
- fileId: string;
67
- progress: number;
68
- status: "uploading" | "processing" | "completed" | "error";
69
- error?: string;
70
- url?: string;
71
- }
72
-
73
- export interface MediaCompressionOptions {
74
- quality: number;
75
- maxWidth?: number;
76
- maxHeight?: number;
77
- maxFileSize?: number;
78
- format?: "jpeg" | "png" | "webp";
79
- }
80
-
81
- export interface MediaFile {
82
- name: string;
83
- type: string;
84
- size: number;
85
- uri?: string;
86
- }
87
-
88
- export interface CreateMultimediaCardData {
89
- front: string;
90
- back: string;
91
- difficulty?: "easy" | "medium" | "hard";
92
- tags?: string[];
93
- media?: MediaAttachment[];
94
- }
95
-
96
- export interface MediaValidation {
97
- isValid: boolean;
98
- errors: string[];
99
- warnings: string[];
100
- recommendations: string[];
101
- }
@@ -1,80 +0,0 @@
1
- /**
2
- * Media Generation Service
3
- * Handles AI media generation (text-to-image, text-to-audio)
4
- */
5
-
6
- import type {
7
- MediaAttachment,
8
- MediaGenerationRequest,
9
- MediaGenerationResult,
10
- MediaType,
11
- MediaPosition,
12
- } from "../../domain/entities/MediaAttachments";
13
-
14
- export class MediaGenerationService {
15
- /**
16
- * Generate media from AI (text-to-image, text-to-audio, etc.)
17
- */
18
- async generateMedia(
19
- request: MediaGenerationRequest,
20
- ): Promise<MediaGenerationResult> {
21
- try {
22
- const startTime = Date.now();
23
-
24
- // Simulate AI generation
25
- await new Promise((resolve) => setTimeout(resolve, 3000));
26
-
27
- const attachments: MediaAttachment[] = [];
28
-
29
- switch (request.type) {
30
- case "text_to_image":
31
- for (let i = 0; i < (request.options.maxResults || 1); i++) {
32
- attachments.push({
33
- id: `ai_img_${Date.now()}_${i}`,
34
- type: "image" as MediaType,
35
- position: "both" as MediaPosition,
36
- url: `https://picsum.photos/400/300?random=${Date.now() + i}`,
37
- filename: `ai_generated_${i}.jpg`,
38
- fileSize: 150000,
39
- mimeType: "image/jpeg",
40
- isDownloaded: false,
41
- createdAt: new Date().toISOString(),
42
- });
43
- }
44
- break;
45
-
46
- case "text_to_audio":
47
- attachments.push({
48
- id: `ai_audio_${Date.now()}`,
49
- type: "audio" as MediaType,
50
- position: "back" as MediaPosition,
51
- url: `https://example.com/audio_${Date.now()}.mp3`,
52
- filename: `ai_generated_${Date.now()}.mp3`,
53
- fileSize: 80000,
54
- mimeType: "audio/mp3",
55
- duration: 10,
56
- isDownloaded: false,
57
- createdAt: new Date().toISOString(),
58
- });
59
- break;
60
- }
61
-
62
- return {
63
- success: true,
64
- attachments,
65
- creditsUsed: request.type === "text_to_image" ? 5 : 3,
66
- processingTime: Date.now() - startTime,
67
- requestId: `req_${Date.now()}`,
68
- };
69
- } catch (error) {
70
- return {
71
- success: false,
72
- attachments: [],
73
- creditsUsed: 0,
74
- processingTime: 0,
75
- error: error instanceof Error ? error.message : "Unknown error",
76
- requestId: "",
77
- };
78
- }
79
- }
80
- }
@@ -1,32 +0,0 @@
1
- /**
2
- * Media Optimizer Service
3
- * Handles media optimization and deletion
4
- */
5
-
6
- import type {
7
- MediaAttachment,
8
- MediaCompressionOptions,
9
- } from "../../domain/entities/MediaAttachments";
10
-
11
- export class MediaOptimizerService {
12
- /**
13
- * Optimize media file
14
- */
15
- async optimizeMedia(
16
- attachment: MediaAttachment,
17
- options: MediaCompressionOptions,
18
- ): Promise<MediaAttachment> {
19
- return {
20
- ...attachment,
21
- fileSize: Math.floor(attachment.fileSize * options.quality),
22
- url: `${attachment.url}?optimized=true`,
23
- };
24
- }
25
-
26
- /**
27
- * Delete media attachment
28
- */
29
- async deleteMedia(_attachmentId: string): Promise<void> {
30
- // Mock implementation
31
- }
32
- }
@@ -1,60 +0,0 @@
1
- /**
2
- * Media Upload Service
3
- * Handles media upload, download, and URL operations
4
- */
5
-
6
- import type {
7
- MediaAttachment,
8
- MediaCompressionOptions,
9
- MediaFile,
10
- } from "../../domain/entities/MediaAttachments";
11
- import { generateThumbnail, getMediaDuration } from "../utils/file-media-utils";
12
- import { getMediaTypeFromMime } from "../utils/mime-type-detector";
13
-
14
- export class MediaUploadService {
15
- /**
16
- * Upload media file with optional compression
17
- */
18
- async uploadMedia(
19
- file: MediaFile,
20
- _options?: MediaCompressionOptions,
21
- ): Promise<MediaAttachment> {
22
- try {
23
- // Simulate upload process
24
- await new Promise((resolve) => setTimeout(resolve, 2000));
25
-
26
- const attachment: MediaAttachment = {
27
- id: `media_${Date.now()}`,
28
- type: getMediaTypeFromMime(file.type),
29
- position: "both",
30
- url: `https://storage.example.com/media/${Date.now()}_${file.name}`,
31
- filename: file.name,
32
- fileSize: file.size || 100000,
33
- mimeType: file.type,
34
- duration: await getMediaDuration(file),
35
- thumbnailUrl: generateThumbnail(file),
36
- caption: "",
37
- isDownloaded: true,
38
- createdAt: new Date().toISOString(),
39
- };
40
-
41
- return attachment;
42
- } catch (error) {
43
- throw new Error(`Failed to upload media: ${error}`);
44
- }
45
- }
46
-
47
- /**
48
- * Get media URL
49
- */
50
- async getMediaUrl(attachmentId: string): Promise<string> {
51
- return `https://storage.example.com/media/${attachmentId}`;
52
- }
53
-
54
- /**
55
- * Download media to local storage
56
- */
57
- async downloadMedia(attachmentId: string): Promise<string> {
58
- return `/local/storage/${attachmentId}`;
59
- }
60
- }
@@ -1,61 +0,0 @@
1
- /**
2
- * Media Validation Service
3
- * Handles media file validation before upload
4
- */
5
-
6
- import { formatFileSize } from "../utils/media-collection-utils";
7
- import type { MediaValidation, MediaFile } from "../../domain/entities/MediaAttachments";
8
-
9
- export class MediaValidationService {
10
- /**
11
- * Validate media file before upload
12
- */
13
- async validateMedia(file: MediaFile): Promise<MediaValidation> {
14
- try {
15
- const errors: string[] = [];
16
- const warnings: string[] = [];
17
- const recommendations: string[] = [];
18
-
19
- // File size validation
20
- const maxSize = 50 * 1024 * 1024; // 50MB
21
- if (file.size > maxSize) {
22
- errors.push(
23
- `File size (${formatFileSize(file.size)}) exceeds maximum allowed size (${formatFileSize(maxSize)})`,
24
- );
25
- } else if (file.size > 10 * 1024 * 1024) {
26
- warnings.push(`Large file size may impact performance`);
27
- recommendations.push("Consider compressing file");
28
- }
29
-
30
- // File type validation
31
- const supportedTypes = [
32
- "image/jpeg",
33
- "image/png",
34
- "image/webp",
35
- "audio/mp3",
36
- "audio/wav",
37
- "audio/m4a",
38
- "video/mp4",
39
- "video/mov",
40
- ];
41
-
42
- if (!supportedTypes.includes(file.type)) {
43
- errors.push(`Unsupported file type: ${file.type}`);
44
- }
45
-
46
- return {
47
- isValid: errors.length === 0,
48
- errors,
49
- warnings,
50
- recommendations,
51
- };
52
- } catch (error) {
53
- return {
54
- isValid: false,
55
- errors: [error instanceof Error ? error.message : "Validation failed"],
56
- warnings: [],
57
- recommendations: [],
58
- };
59
- }
60
- }
61
- }
@@ -1,96 +0,0 @@
1
- /**
2
- * Multimedia Flashcard Service
3
- * Media attachments for flashcards - Main entry point
4
- */
5
-
6
- import type {
7
- MediaAttachment,
8
- MediaFile,
9
- MediaGenerationRequest,
10
- MediaGenerationResult,
11
- MediaCompressionOptions,
12
- MediaValidation,
13
- } from "../../domain/entities/MediaAttachments";
14
- import { MediaUploadService } from "./MediaUploadService";
15
- import { MediaGenerationService } from "./MediaGenerationService";
16
- import { MediaValidationService } from "./MediaValidationService";
17
- import { MediaOptimizerService } from "./MediaOptimizerService";
18
-
19
- export class MultimediaFlashcardService {
20
- private static instance: MultimediaFlashcardService;
21
- private uploadService: MediaUploadService;
22
- private generationService: MediaGenerationService;
23
- private validationService: MediaValidationService;
24
- private optimizerService: MediaOptimizerService;
25
-
26
- private constructor() {
27
- this.uploadService = new MediaUploadService();
28
- this.generationService = new MediaGenerationService();
29
- this.validationService = new MediaValidationService();
30
- this.optimizerService = new MediaOptimizerService();
31
- }
32
-
33
- static getInstance(): MultimediaFlashcardService {
34
- if (!MultimediaFlashcardService.instance) {
35
- MultimediaFlashcardService.instance = new MultimediaFlashcardService();
36
- }
37
- return MultimediaFlashcardService.instance;
38
- }
39
-
40
- /**
41
- * Upload media file with optional compression
42
- */
43
- async uploadMedia(
44
- file: MediaFile,
45
- options?: MediaCompressionOptions,
46
- ): Promise<MediaAttachment> {
47
- return this.uploadService.uploadMedia(file, options);
48
- }
49
-
50
- /**
51
- * Generate media from AI (text-to-image, text-to-audio, etc.)
52
- */
53
- async generateMedia(
54
- request: MediaGenerationRequest,
55
- ): Promise<MediaGenerationResult> {
56
- return this.generationService.generateMedia(request);
57
- }
58
-
59
- /**
60
- * Validate media file before upload
61
- */
62
- async validateMedia(file: MediaFile): Promise<MediaValidation> {
63
- return this.validationService.validateMedia(file);
64
- }
65
-
66
- /**
67
- * Optimize media file
68
- */
69
- async optimizeMedia(
70
- attachment: MediaAttachment,
71
- options: MediaCompressionOptions,
72
- ): Promise<MediaAttachment> {
73
- return this.optimizerService.optimizeMedia(attachment, options);
74
- }
75
-
76
- /**
77
- * Delete media attachment
78
- */
79
- async deleteMedia(attachmentId: string): Promise<void> {
80
- return this.optimizerService.deleteMedia(attachmentId);
81
- }
82
-
83
- /**
84
- * Get media URL
85
- */
86
- async getMediaUrl(attachmentId: string): Promise<string> {
87
- return this.uploadService.getMediaUrl(attachmentId);
88
- }
89
-
90
- /**
91
- * Download media to local storage
92
- */
93
- async downloadMedia(attachmentId: string): Promise<string> {
94
- return this.uploadService.downloadMedia(attachmentId);
95
- }
96
- }
@@ -1,53 +0,0 @@
1
- /**
2
- * Multimedia Flashcard Hook Types
3
- * Type definitions for multimedia hooks
4
- */
5
-
6
- import type {
7
- MediaAttachment,
8
- MediaFile,
9
- MediaGenerationRequest,
10
- MediaGenerationResult,
11
- MediaCompressionOptions,
12
- MediaValidation,
13
- MediaUploadProgress,
14
- MultimediaFlashcard,
15
- CreateMultimediaCardData,
16
- } from "../../domain/entities/MediaAttachments";
17
-
18
- export interface UseMediaUploadResult {
19
- uploadMedia: (
20
- file: MediaFile,
21
- options?: MediaCompressionOptions,
22
- ) => Promise<MediaAttachment>;
23
- isUploading: boolean;
24
- uploadProgress: MediaUploadProgress | null;
25
- error: string | null;
26
- }
27
-
28
- export interface UseMediaGenerationResult {
29
- generateMedia: (
30
- request: MediaGenerationRequest,
31
- ) => Promise<MediaGenerationResult>;
32
- isGenerating: boolean;
33
- generationResult: MediaGenerationResult | null;
34
- error: string | null;
35
- }
36
-
37
- export interface UseMediaValidationResult {
38
- validateMedia: (file: MediaFile) => Promise<MediaValidation>;
39
- isValidating: boolean;
40
- validation: MediaValidation | null;
41
- error: string | null;
42
- }
43
-
44
- export interface UseMultimediaFlashcardResult {
45
- createMultimediaCard: (cardData: CreateMultimediaCardData) => Promise<MultimediaFlashcard>;
46
- updateMedia: (
47
- cardId: string,
48
- media: MediaAttachment[],
49
- ) => Promise<MultimediaFlashcard>;
50
- deleteMedia: (attachmentId: string) => Promise<void>;
51
- isProcessing: boolean;
52
- error: string | null;
53
- }
@@ -1,102 +0,0 @@
1
- /**
2
- * Card Multimedia Flashcard Hooks
3
- * Main hook and exports for card multimedia functionality
4
- */
5
-
6
- import { useState, useCallback } from "react";
7
- import { calculateTotalSize, extractMediaTypes } from "../../infrastructure/utils/media-collection-utils";
8
- import type { UseCardMultimediaFlashcardResult } from "./card-multimedia.types";
9
- import type {
10
- MediaAttachment as CardMediaAttachment,
11
- MultimediaFlashcard as CardMultimediaFlashcard,
12
- CreateMultimediaCardData as CreateCardMultimediaData,
13
- } from "../../domain/entities/MediaAttachments";
14
-
15
- // Export individual hooks
16
- export { useCardMediaUpload } from "./useCardMediaUpload";
17
- export { useCardMediaGeneration } from "./useCardMediaGeneration";
18
- export { useCardMediaValidation } from "./useCardMediaValidation";
19
-
20
- // Export types
21
- export type {
22
- UseCardMediaUploadResult,
23
- UseCardMediaGenerationResult,
24
- UseCardMediaValidationResult,
25
- UseCardMultimediaFlashcardResult,
26
- } from "./card-multimedia.types";
27
-
28
- /**
29
- * Main hook for card multimedia flashcard operations
30
- */
31
- export const useCardMultimediaFlashcard =
32
- (): UseCardMultimediaFlashcardResult => {
33
- const [isProcessing, setIsProcessing] = useState(false);
34
- const [error, setError] = useState<string | null>(null);
35
-
36
- const createCardMultimedia = useCallback(
37
- async (cardData: CreateCardMultimediaData): Promise<CardMultimediaFlashcard> => {
38
- try {
39
- setIsProcessing(true);
40
- setError(null);
41
-
42
- // Simulate card creation
43
- await new Promise((resolve) => setTimeout(resolve, 1000));
44
-
45
- const card: CardMultimediaFlashcard = {
46
- id: `card_multimedia_${Date.now()}`,
47
- front: cardData.front || "",
48
- back: cardData.back || "",
49
- difficulty: cardData.difficulty || "medium",
50
- tags: cardData.tags || [],
51
- media: cardData.media || [],
52
- hasMedia: (cardData.media || []).length > 0,
53
- mediaType: extractMediaTypes(cardData.media || []),
54
- isDownloaded: (cardData.media || []).every(
55
- (m: CardMediaAttachment) => m.isDownloaded,
56
- ),
57
- estimatedSize: calculateTotalSize(cardData.media || []),
58
- createdAt: new Date().toISOString(),
59
- };
60
-
61
- return card;
62
- } catch (err) {
63
- const errorMessage =
64
- err instanceof Error ? err.message : "Card creation failed";
65
- setError(errorMessage);
66
- setIsProcessing(false);
67
- throw err;
68
- } finally {
69
- setIsProcessing(false);
70
- }
71
- },
72
- [],
73
- );
74
-
75
- const updateCardMedia = useCallback(
76
- async (
77
- _cardId: string,
78
- _media: CardMediaAttachment[],
79
- ): Promise<CardMultimediaFlashcard> => {
80
- // Mock implementation
81
- await new Promise((resolve) => setTimeout(resolve, 500));
82
- return {} as CardMultimediaFlashcard;
83
- },
84
- [],
85
- );
86
-
87
- const deleteCardMedia = useCallback(
88
- async (_attachmentId: string): Promise<void> => {
89
- // Mock implementation
90
- await new Promise((resolve) => setTimeout(resolve, 500));
91
- },
92
- [],
93
- );
94
-
95
- return {
96
- createCardMultimedia,
97
- updateCardMedia,
98
- deleteCardMedia,
99
- isProcessing,
100
- error,
101
- };
102
- };
@@ -1,18 +0,0 @@
1
- /**
2
- * Media Generation Hook
3
- * Hook for generating media with AI
4
- * Now a thin wrapper around useGenericMediaGeneration
5
- */
6
-
7
- import { useGenericMediaGeneration } from "../../infrastructure/hooks/useGenericMediaGeneration";
8
- import type { UseMediaGenerationResult } from "./multimedia.types";
9
- import type {
10
- MediaAttachment,
11
- MediaGenerationRequest,
12
- } from "../../domain/entities/MediaAttachments";
13
-
14
- export const useMediaGeneration = (): UseMediaGenerationResult => {
15
- return useGenericMediaGeneration<MediaAttachment, MediaGenerationRequest>(
16
- (baseAttachment) => baseAttachment as MediaAttachment
17
- );
18
- };
@@ -1,84 +0,0 @@
1
- /**
2
- * Media Upload Hook
3
- * Hook for uploading media files
4
- */
5
-
6
- import { useState, useCallback } from "react";
7
- import { generateThumbnail, getMediaDuration } from "../../infrastructure/utils/file-media-utils";
8
- import { getMediaTypeFromMime } from "../../infrastructure/utils/mime-type-detector";
9
- import type { UseMediaUploadResult } from "./multimedia.types";
10
- import type {
11
- MediaAttachment,
12
- MediaCompressionOptions,
13
- MediaFile,
14
- MediaUploadProgress,
15
- } from "../../domain/entities/MediaAttachments";
16
-
17
- export const useMediaUpload = (): UseMediaUploadResult => {
18
- const [isUploading, setIsUploading] = useState(false);
19
- const [uploadProgress, setUploadProgress] =
20
- useState<MediaUploadProgress | null>(null);
21
- const [error, setError] = useState<string | null>(null);
22
-
23
- const uploadMedia = useCallback(
24
- async (file: MediaFile, _options?: MediaCompressionOptions) => {
25
- try {
26
- setIsUploading(true);
27
- setError(null);
28
-
29
- // Simulate upload progress
30
- setUploadProgress({
31
- fileId: `upload_${Date.now()}`,
32
- progress: 0,
33
- status: "uploading",
34
- });
35
-
36
- // Simulate progress updates
37
- for (let i = 1; i <= 100; i += 10) {
38
- await new Promise((resolve) => setTimeout(resolve, 100));
39
- setUploadProgress((prev) => (prev ? { ...prev, progress: i } : null));
40
- }
41
-
42
- const attachment: MediaAttachment = {
43
- id: `media_${Date.now()}`,
44
- type: getMediaTypeFromMime(file.type),
45
- position: "both",
46
- url: `https://storage.example.com/media/${Date.now()}_${file.name}`,
47
- filename: file.name,
48
- fileSize: file.size || 100000,
49
- mimeType: file.type,
50
- duration: await getMediaDuration(file),
51
- thumbnailUrl: generateThumbnail(file),
52
- caption: "",
53
- isDownloaded: true,
54
- createdAt: new Date().toISOString(),
55
- };
56
-
57
- setUploadProgress({
58
- fileId: `upload_${Date.now()}`,
59
- progress: 100,
60
- status: "completed",
61
- url: attachment.url,
62
- });
63
-
64
- return attachment;
65
- } catch (err) {
66
- const errorMessage =
67
- err instanceof Error ? err.message : "Upload failed";
68
- setError(errorMessage);
69
- setIsUploading(false);
70
- throw err;
71
- } finally {
72
- setIsUploading(false);
73
- }
74
- },
75
- [],
76
- );
77
-
78
- return {
79
- uploadMedia,
80
- isUploading,
81
- uploadProgress,
82
- error,
83
- };
84
- };
@@ -1,93 +0,0 @@
1
- /**
2
- * Media Validation Hook
3
- * Hook for validating media files
4
- */
5
-
6
- import { useState, useCallback } from "react";
7
- import { formatFileSize } from "../../infrastructure/utils/media-collection-utils";
8
- import type { UseMediaValidationResult } from "./multimedia.types";
9
- import type { MediaValidation, MediaFile } from "../../domain/entities/MediaAttachments";
10
-
11
- export const useMediaValidation = (): UseMediaValidationResult => {
12
- const [isValidating, setIsValidating] = useState(false);
13
- const [validation, setValidation] = useState<MediaValidation | null>(
14
- null,
15
- );
16
- const [error, setError] = useState<string | null>(null);
17
-
18
- const validateMedia = useCallback(
19
- async (file: MediaFile): Promise<MediaValidation> => {
20
- try {
21
- setIsValidating(true);
22
- setError(null);
23
-
24
- // Simulate validation
25
- await new Promise((resolve) => setTimeout(resolve, 500));
26
-
27
- const errors: string[] = [];
28
- const warnings: string[] = [];
29
- const recommendations: string[] = [];
30
-
31
- // File size validation
32
- const maxSize = 50 * 1024 * 1024; // 50MB
33
- if (file.size > maxSize) {
34
- errors.push(
35
- `File size (${formatFileSize(file.size)}) exceeds maximum allowed size (${formatFileSize(maxSize)})`,
36
- );
37
- } else if (file.size > 10 * 1024 * 1024) {
38
- // 10MB
39
- warnings.push(`Large file size may impact performance`);
40
- recommendations.push("Consider compressing file");
41
- }
42
-
43
- // File type validation
44
- const supportedTypes = [
45
- "image/jpeg",
46
- "image/png",
47
- "image/webp",
48
- "audio/mp3",
49
- "audio/wav",
50
- "audio/m4a",
51
- "video/mp4",
52
- "video/mov",
53
- ];
54
-
55
- if (!supportedTypes.includes(file.type)) {
56
- errors.push(`Unsupported file type: ${file.type}`);
57
- }
58
-
59
- const result: MediaValidation = {
60
- isValid: errors.length === 0,
61
- errors,
62
- warnings,
63
- recommendations,
64
- };
65
-
66
- setValidation(result);
67
- return result;
68
- } catch (err) {
69
- const errorMessage =
70
- err instanceof Error ? err.message : "Validation failed";
71
- setError(errorMessage);
72
- setIsValidating(false);
73
-
74
- return {
75
- isValid: false,
76
- errors: [errorMessage],
77
- warnings: [],
78
- recommendations: [],
79
- };
80
- } finally {
81
- setIsValidating(false);
82
- }
83
- },
84
- [],
85
- );
86
-
87
- return {
88
- validateMedia,
89
- isValidating,
90
- validation,
91
- error,
92
- };
93
- };
@@ -1,101 +0,0 @@
1
- /**
2
- * Multimedia Flashcard Hooks
3
- * Main hook and exports for multimedia functionality
4
- */
5
-
6
- import { useState, useCallback } from "react";
7
- import { calculateTotalSize, extractMediaTypes } from "../../infrastructure/utils/media-collection-utils";
8
- import type { UseMultimediaFlashcardResult } from "./multimedia.types";
9
- import type {
10
- MediaAttachment,
11
- MultimediaFlashcard,
12
- CreateMultimediaCardData,
13
- } from "../../domain/entities/MediaAttachments";
14
-
15
- // Export individual hooks
16
- export { useMediaUpload } from "./useMediaUpload";
17
- export { useMediaGeneration } from "./useMediaGeneration";
18
- export { useMediaValidation } from "./useMediaValidation";
19
-
20
- // Export types
21
- export type {
22
- UseMediaUploadResult,
23
- UseMediaGenerationResult,
24
- UseMediaValidationResult,
25
- UseMultimediaFlashcardResult,
26
- } from "./multimedia.types";
27
-
28
- /**
29
- * Main hook for multimedia flashcard operations
30
- */
31
- export const useMultimediaFlashcard = (): UseMultimediaFlashcardResult => {
32
- const [isProcessing, setIsProcessing] = useState(false);
33
- const [error, setError] = useState<string | null>(null);
34
-
35
- const createMultimediaCard = useCallback(
36
- async (cardData: CreateMultimediaCardData): Promise<MultimediaFlashcard> => {
37
- try {
38
- setIsProcessing(true);
39
- setError(null);
40
-
41
- // Simulate card creation
42
- await new Promise((resolve) => setTimeout(resolve, 1000));
43
-
44
- const card: MultimediaFlashcard = {
45
- id: `card_${Date.now()}`,
46
- front: cardData.front || "",
47
- back: cardData.back || "",
48
- difficulty: cardData.difficulty || "medium",
49
- tags: cardData.tags || [],
50
- media: cardData.media || [],
51
- hasMedia: (cardData.media || []).length > 0,
52
- mediaType: extractMediaTypes(cardData.media || []),
53
- isDownloaded: (cardData.media || []).every(
54
- (m: MediaAttachment) => m.isDownloaded,
55
- ),
56
- estimatedSize: calculateTotalSize(cardData.media || []),
57
- createdAt: new Date().toISOString(),
58
- };
59
-
60
- return card;
61
- } catch (err) {
62
- const errorMessage =
63
- err instanceof Error ? err.message : "Card creation failed";
64
- setError(errorMessage);
65
- setIsProcessing(false);
66
- throw err;
67
- } finally {
68
- setIsProcessing(false);
69
- }
70
- },
71
- [],
72
- );
73
-
74
- const updateMedia = useCallback(
75
- async (
76
- _cardId: string,
77
- _media: MediaAttachment[],
78
- ): Promise<MultimediaFlashcard> => {
79
- // Mock implementation
80
- await new Promise((resolve) => setTimeout(resolve, 500));
81
- return {} as MultimediaFlashcard;
82
- },
83
- [],
84
- );
85
-
86
- const deleteMedia = useCallback(
87
- async (_attachmentId: string): Promise<void> => {
88
- // Mock implementation
89
- await new Promise((resolve) => setTimeout(resolve, 500));
90
- },
91
- [],
92
- );
93
-
94
- return {
95
- createMultimediaCard,
96
- updateMedia,
97
- deleteMedia,
98
- isProcessing,
99
- error,
100
- };
101
- };