@kodeme-io/next-core-storage-react
v0.8.4
Published
React hooks for @kodeme-io/next-core-storage
Maintainers
Readme
@next-core-storage-react
React hooks for the enhanced Next.js storage package with progress tracking, smart compression, and batch upload capabilities.
Installation
npm install @kodeme-io/next-core-storage-react @kodeme-io/next-core-storage reactQuick Start
Basic Upload with Progress
import { useUpload } from '@kodeme-io/next-core-storage-react'
import { createS3Client } from '@kodeme-io/next-core-storage'
function UploadComponent() {
const client = createS3Client({
endpoint: process.env.S3_ENDPOINT_URL!,
accessKeyId: process.env.S3_ACCESS_KEY!,
secretAccessKey: process.env.S3_SECRET_KEY!,
bucket: process.env.S3_BUCKET_NAME!,
})
const {
upload,
progress,
isUploading,
error,
result
} = useUpload(client, process.env.S3_BUCKET_NAME!, {
onSuccess: (result) => console.log('Upload complete:', result.url),
onError: (error) => console.error('Upload failed:', error)
})
const handleFileSelect = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0]
if (!file) return
try {
const base64 = await fileToBase64(file)
await upload(base64, file.name, file.type, 'uploads')
} catch (error) {
console.error('Error:', error)
}
}
return (
<div>
<input type="file" onChange={handleFileSelect} disabled={isUploading} />
{isUploading && (
<div>
<div>Uploading... {progress?.percentage.toFixed(1)}%</div>
<div>Speed: {progress?.speed ? (progress.speed / 1024).toFixed(1) : 0} KB/s</div>
<div>ETA: {progress?.eta ? Math.round(progress.eta) : 0}s</div>
</div>
)}
{error && <div style={{ color: 'red' }}>Error: {error.message}</div>}
{result && (
<div>
<div>Upload complete!</div>
<a href={result.url} target="_blank" rel="noopener noreferrer">
View file
</a>
</div>
)}
</div>
)
}Smart Photo Compression
import { useSmartCompression } from '@kodeme-io/next-core-storage-react'
function PhotoUpload() {
const {
compress,
isCompressing,
result,
originalSize,
compressedSize,
compressionRatio,
format
} = useSmartCompression({
onSuccess: (compressedFile) => {
console.log('Photo compressed:', {
original: originalSize,
compressed: compressedSize,
ratio: compressionRatio,
format
})
}
})
const handlePhoto = async (file: File) => {
try {
const compressed = await compress(file, {
smartFormat: true,
maxWidth: 1920,
maxHeight: 1080,
maxSize: 400 * 1024 // 400KB
})
// Upload compressed photo
// await uploadPhoto(compressed)
} catch (error) {
console.error('Compression failed:', error)
}
}
return (
<div>
<input
type="file"
accept="image/*"
onChange={(e) => e.target.files?.[0] && handlePhoto(e.target.files[0])}
disabled={isCompressing}
/>
{isCompressing && <div>Compressing photo...</div>}
{result && (
<div>
<div>✅ Compression complete</div>
<div>Original: {(originalSize / 1024).toFixed(1)} KB</div>
<div>Compressed: {(compressedSize / 1024).toFixed(1)} KB</div>
<div>Saved: {compressionRatio.toFixed(1)}%</div>
<div>Format: {format}</div>
</div>
)}
</div>
)
}Batch Upload Queue
import { useUploadQueue } from '@kodeme-io/next-core-storage-react'
function BatchUploader() {
const {
addJob,
addBatch,
pause,
resume,
clear,
status,
jobs,
isProcessing
} = useUploadQueue(client, bucket, {
maxConcurrency: 3,
onQueueComplete: (result) => {
console.log(`Batch complete: ${result.successful.length}/${result.total} successful`)
}
})
const handleMultipleFiles = async (files: FileList) => {
const uploadJobs = Array.from(files).map(file => ({
file: await fileToBase64(file),
fileName: file.name,
contentType: file.type,
folder: 'batch-uploads',
priority: 'normal' as const
}))
addBatch(uploadJobs)
}
return (
<div>
<input
type="file"
multiple
onChange={(e) => e.target.files && handleMultipleFiles(e.target.files)}
/>
<div>
<button onClick={pause} disabled={!isProcessing}>Pause</button>
<button onClick={resume} disabled={isProcessing}>Resume</button>
<button onClick={clear}>Clear Completed</button>
</div>
<div>
<div>Pending: {status.pending}</div>
<div>Active: {status.active}</div>
<div>Completed: {status.completed}</div>
<div>Failed: {status.failed}</div>
</div>
<div>
{jobs.map(job => (
<div key={job.id}>
{job.fileName} - {job.status}
{job.progress && (
<span> ({job.progress.percentage.toFixed(1)}%)</span>
)}
</div>
))}
</div>
</div>
)
}Hooks Reference
useUpload(client, bucket, options?)
Hook for single file uploads with progress tracking.
Parameters:
client: S3Client instancebucket: S3 bucket nameoptions: Upload options and callbacks
Returns:
{
upload: (file, fileName, contentType, folder?, endpoint?) => Promise<UploadResult>
cancel: () => void
reset: () => void
progress: UploadProgress | null
isUploading: boolean
error: Error | null
result: UploadResult | null
}useVisitPhotoUpload(client, bucket, options?)
Specialized hook for visit photo uploads with organized folder structure.
Returns:
{
upload: (base64Data, visitId, photoType, endpoint?) => Promise<VisitPhotoUploadResult>
cancel: () => void
reset: () => void
progress: UploadProgress | null
isUploading: boolean
error: Error | null
result: VisitPhotoUploadResult | null
}useSmartCompression(options?)
Hook for intelligent photo compression with automatic format selection.
Returns:
{
compress: (file, options?) => Promise<File>
reset: () => void
isCompressing: boolean
error: Error | null
result: File | null
originalSize: number
compressedSize: number
compressionRatio: number
format: string
}useUploadQueue(client, bucket, options?)
Hook for managing multiple concurrent uploads with queue control.
Returns:
{
addJob: (job, priority?) => string
addBatch: (jobs) => string[]
removeJob: (jobId) => boolean
cancelJob: (jobId) => boolean
pause: () => void
resume: () => void
clear: () => void
getJob: (jobId) => UploadJob | undefined
retryFailedJobs: () => void
status: QueueStatus
jobs: UploadJob[]
isProcessing: boolean
error: Error | null
}useCompression(options?)
Basic photo compression hook.
Returns:
{
compress: (file, options?) => Promise<File>
reset: () => void
isCompressing: boolean
error: Error | null
result: File | null
originalSize: number
compressedSize: number
compressionRatio: number
}useBatchCompression(options?)
Hook for batch compression operations.
Returns:
{
compressBatch: (files, options?) => Promise<File[]>
compressSmartBatch: (files, options?) => Promise<File[]>
reset: () => void
isCompressing: boolean
error: Error | null
results: File[]
progress: number
total: number
}useStorageQuota()
Hook for browser storage quota information.
Returns:
{
quota: StorageQuota | null
loading: boolean
error: Error | null
refresh: () => Promise<StorageQuota | null>
}Examples
Photo Upload with Compression and Progress
function PhotoUploader() {
const [file, setFile] = useState<File | null>(null)
const { compress, isCompressing, result: compressedFile } = useSmartCompression()
const { upload, progress, isUploading } = useUpload(client, bucket)
const handleUpload = async () => {
if (!file) return
try {
// Step 1: Compress photo
const compressed = await compress(file, {
smartFormat: true,
maxSize: 500 * 1024 // 500KB
})
// Step 2: Upload compressed photo
const base64 = await fileToBase64(compressed)
await upload(base64, file.name, compressed.type, 'photos')
} catch (error) {
console.error('Upload failed:', error)
}
}
return (
<div>
<input
type="file"
accept="image/*"
onChange={(e) => setFile(e.target.files?.[0] || null)}
/>
<button
onClick={handleUpload}
disabled={!file || isCompressing || isUploading}
>
{isCompressing ? 'Compressing...' : isUploading ? 'Uploading...' : 'Upload'}
</button>
{progress && (
<div>
<div>Progress: {progress.percentage.toFixed(1)}%</div>
<div>Speed: {(progress.speed / 1024).toFixed(1)} KB/s</div>
<div>ETA: {Math.round(progress.eta)}s</div>
</div>
)}
</div>
)
}TypeScript Support
All hooks are fully typed with TypeScript. Import types:
import type {
UseUploadState,
UseCompressionState,
UploadProgress,
CompressionOptions
} from '@kodeme-io/next-core-storage-react'License
MIT
Built with ❤️ by ABC Food Development Team
