122 lines
4.2 KiB
TypeScript
122 lines
4.2 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { useState } from "react";
|
||
|
|
import { Box, Button, Typography, Paper, LinearProgress, Stack } from "@mui/material";
|
||
|
|
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
|
||
|
|
import { uploadFileAction } from "./_actions";
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Helper function to convert raw bytes into a human-readable string.
|
||
|
|
* This helps the user understand exactly how large their e-book is.
|
||
|
|
*/
|
||
|
|
const formatFileSize = (bytes: number) => {
|
||
|
|
if (bytes === 0) return '0 Bytes';
|
||
|
|
const k = 1024;
|
||
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||
|
|
// Returns something like "1.45 MB" or "850 KB"
|
||
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||
|
|
};
|
||
|
|
|
||
|
|
export default function UploadView({ user }: { user: any }) {
|
||
|
|
const [file, setFile] = useState<File | null>(null);
|
||
|
|
const [status, setStatus] = useState<'idle' | 'uploading' | 'success'>('idle');
|
||
|
|
|
||
|
|
const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB Limit
|
||
|
|
|
||
|
|
const handleUpload = async () => {
|
||
|
|
if (!file) return;
|
||
|
|
if (file.size > MAX_FILE_SIZE) {
|
||
|
|
alert(`File is too large! Maximum size allowed is ${formatFileSize(MAX_FILE_SIZE)}.`);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
setStatus('uploading');
|
||
|
|
|
||
|
|
const formData = new FormData();
|
||
|
|
formData.append("file", file);
|
||
|
|
|
||
|
|
try {
|
||
|
|
await uploadFileAction(formData);
|
||
|
|
setStatus('success');
|
||
|
|
setFile(null);
|
||
|
|
} catch (err) {
|
||
|
|
// If the server action fails, it usually prints details in the terminal
|
||
|
|
alert("Upload failed. Ensure the 'WebCalibre' folder can be created and OneDrive has space.");
|
||
|
|
setStatus('idle');
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Paper sx={{ p: 6, textAlign: 'center', borderRadius: 4 }} elevation={3}>
|
||
|
|
<Typography variant="h4" fontWeight={900} color="primary" gutterBottom>
|
||
|
|
Upload to WebCalibre
|
||
|
|
</Typography>
|
||
|
|
<Typography variant="body1" color="text.secondary" mb={4}>
|
||
|
|
Adding books as <strong>{user.name}</strong>
|
||
|
|
</Typography>
|
||
|
|
|
||
|
|
<Stack spacing={3} alignItems="center">
|
||
|
|
{/* Dropzone/Selection Area */}
|
||
|
|
<Box sx={{ width: '100%', p: 5, border: '2px dashed #ccc', borderRadius: 2, bgcolor: '#f9f9f9' }}>
|
||
|
|
<input
|
||
|
|
type="file"
|
||
|
|
id="book-upload"
|
||
|
|
hidden
|
||
|
|
// Only allow common book formats
|
||
|
|
accept=".pdf,.epub,.mobi,.azw3,.txt"
|
||
|
|
onChange={(e) => {
|
||
|
|
setFile(e.target.files?.[0] || null);
|
||
|
|
setStatus('idle');
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
<label htmlFor="book-upload">
|
||
|
|
<Button variant="outlined" component="span" startIcon={<CloudUploadIcon />}>
|
||
|
|
{file ? "Select Different File" : "Choose File (PDF, EPUB, MOBI)"}
|
||
|
|
</Button>
|
||
|
|
</label>
|
||
|
|
|
||
|
|
{/* New: Enhanced File Info Display */}
|
||
|
|
{file && (
|
||
|
|
<Box mt={3}>
|
||
|
|
<Typography variant="subtitle2" color="primary.main" fontWeight="bold">
|
||
|
|
Selected: {file.name}
|
||
|
|
</Typography>
|
||
|
|
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 0.5 }}>
|
||
|
|
File Size: {formatFileSize(file.size)}
|
||
|
|
</Typography>
|
||
|
|
</Box>
|
||
|
|
)}
|
||
|
|
</Box>
|
||
|
|
|
||
|
|
{/* Progress Indicator */}
|
||
|
|
{status === 'uploading' && (
|
||
|
|
<Box sx={{ width: '100%' }}>
|
||
|
|
<Typography variant="caption" display="block" gutterBottom sx={{ color: 'primary.main', fontWeight: 600 }}>
|
||
|
|
Connecting to OneDrive & Uploading...
|
||
|
|
</Typography>
|
||
|
|
<LinearProgress />
|
||
|
|
</Box>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Action Button */}
|
||
|
|
<Button
|
||
|
|
variant="contained"
|
||
|
|
size="large"
|
||
|
|
fullWidth
|
||
|
|
disabled={!file || status === 'uploading'}
|
||
|
|
onClick={handleUpload}
|
||
|
|
sx={{ py: 1.5, fontSize: '1.1rem', fontWeight: 700 }}
|
||
|
|
>
|
||
|
|
{status === 'uploading' ? 'Please Wait...' : 'Confirm Upload'}
|
||
|
|
</Button>
|
||
|
|
|
||
|
|
{/* Success Feedback */}
|
||
|
|
{status === 'success' && (
|
||
|
|
<Typography color="success.main" fontWeight="bold" sx={{ mt: 2 }}>
|
||
|
|
✅ Successfully uploaded to your library!
|
||
|
|
</Typography>
|
||
|
|
)}
|
||
|
|
</Stack>
|
||
|
|
</Paper>
|
||
|
|
);
|
||
|
|
}
|