fixed file creation bug

This commit is contained in:
stephen 2026-02-07 12:33:43 +11:00
parent 552662cf16
commit 672408081d
3 changed files with 12401 additions and 39 deletions

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -6,7 +6,7 @@ import {
TextField, IconButton, Divider, TextField, IconButton, Divider,
Grid, Grid,
CircularProgress, Checkbox, MenuItem, CircularProgress, Checkbox, MenuItem,
InputAdornment, Collapse Collapse
} from "@mui/material"; } from "@mui/material";
import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh'; import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh';
import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'; import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline';
@ -26,7 +26,7 @@ interface MetadataRow {
selected?: boolean; selected?: boolean;
} }
export default function UploadView({ user, folders }: { user: any; folders: any[] }) { export default function UploadView({ folders }: { user: any; folders: any[] }) {
const router = useRouter(); const router = useRouter();
const fileInputRef = useRef<HTMLInputElement>(null); const fileInputRef = useRef<HTMLInputElement>(null);
@ -50,9 +50,10 @@ export default function UploadView({ user, folders }: { user: any; folders: any[
const result = await getMetadataPreviewAction(selectedFile.name); const result = await getMetadataPreviewAction(selectedFile.name);
if (result.success) { if (result.success) {
// Map data from the new extractor (PDF or Image)
const extractedRows: MetadataRow[] = Object.entries(result.data ?? {}).map(([k, v]) => ({ const extractedRows: MetadataRow[] = Object.entries(result.data ?? {}).map(([k, v]) => ({
key: k, key: k,
value: String(v), value: typeof v === 'object' ? JSON.stringify(v) : String(v),
isPending: true, isPending: true,
selected: true selected: true
})); }));
@ -74,6 +75,8 @@ export default function UploadView({ user, folders }: { user: any; folders: any[
const file = e.target.files?.[0]; const file = e.target.files?.[0];
if (file) { if (file) {
setSelectedFile(file); setSelectedFile(file);
// Optional: Auto-run magic enhance on file selection
// handleMagicEnhance();
} }
}; };
@ -89,8 +92,10 @@ export default function UploadView({ user, folders }: { user: any; folders: any[
if (newFolderName.trim()) { if (newFolderName.trim()) {
const folderResult = await createFolderAction(newFolderName, targetFolderId || null); const folderResult = await createFolderAction(newFolderName, targetFolderId || null);
if (folderResult.success) { if (folderResult.success) {
// If successful, we want the file to go inside this NEW folder // If successful, the file goes inside this NEW folder
currentParentId = folderResult.node.id; currentParentId = folderResult.node.id;
} else {
throw new Error(folderResult.error || "Failed to create folder");
} }
} }
@ -117,7 +122,6 @@ export default function UploadView({ user, folders }: { user: any; folders: any[
} }
} }
console.log("✅ Process complete. Returning to dashboard.");
router.push("/dashboard"); router.push("/dashboard");
router.refresh(); router.refresh();
} catch (err: any) { } catch (err: any) {
@ -129,7 +133,7 @@ export default function UploadView({ user, folders }: { user: any; folders: any[
}; };
return ( return (
<Paper sx={{ p: { xs: 3, md: 6 }, borderRadius: 4, maxWidth: 800, mx: 'auto' }} elevation={3}> <Paper sx={{ p: { xs: 3, md: 6 }, borderRadius: 4, maxWidth: 800, mx: 'auto', mt: 4 }} elevation={3}>
<Typography variant="h4" fontWeight={900} color="primary" gutterBottom align="center"> <Typography variant="h4" fontWeight={900} color="primary" gutterBottom align="center">
Upload & Enrich Upload & Enrich
</Typography> </Typography>
@ -141,12 +145,10 @@ export default function UploadView({ user, folders }: { user: any; folders: any[
<TextField <TextField
select select
fullWidth fullWidth
label="Destination Folder" label="Parent Destination"
value={targetFolderId} value={targetFolderId}
onChange={(e) => { onChange={(e) => setTargetFolderId(e.target.value)}
setTargetFolderId(e.target.value); helperText="Choose where your file (and new folder) will live"
if (e.target.value) setShowNewFolderInput(false);
}}
> >
<MenuItem value=""><em>-- Root Directory --</em></MenuItem> <MenuItem value=""><em>-- Root Directory --</em></MenuItem>
{folders?.map((f) => ( {folders?.map((f) => (
@ -155,23 +157,23 @@ export default function UploadView({ user, folders }: { user: any; folders: any[
</TextField> </TextField>
<Button <Button
variant={showNewFolderInput ? "contained" : "outlined"} variant={showNewFolderInput ? "contained" : "outlined"}
onClick={() => { onClick={() => setShowNewFolderInput(!showNewFolderInput)}
setShowNewFolderInput(!showNewFolderInput);
if (!showNewFolderInput) setTargetFolderId("");
}}
sx={{ height: 56, minWidth: 56 }} sx={{ height: 56, minWidth: 56 }}
title="Create a new sub-folder"
> >
<CreateNewFolderIcon /> <CreateNewFolderIcon />
</Button> </Button>
</Stack> </Stack>
<Collapse in={showNewFolderInput}> <Collapse in={showNewFolderInput}>
<Box sx={{ mt: 2, p: 2, bgcolor: 'grey.50', borderRadius: 2 }}> <Box sx={{ mt: 2, p: 2, bgcolor: 'grey.50', borderRadius: 2, border: '1px solid', borderColor: 'divider' }}>
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mb: 1 }}>
NEW SUB-FOLDER NAME
</Typography>
<TextField <TextField
fullWidth fullWidth
size="small" size="small"
label="New Folder Name" placeholder="e.g. Invoices 2026"
placeholder="Enter name to create folder..."
value={newFolderName} value={newFolderName}
onChange={(e) => setNewFolderName(e.target.value)} onChange={(e) => setNewFolderName(e.target.value)}
/> />
@ -194,17 +196,17 @@ export default function UploadView({ user, folders }: { user: any; folders: any[
fullWidth fullWidth
startIcon={<CloudUploadIcon />} startIcon={<CloudUploadIcon />}
onClick={() => fileInputRef.current?.click()} onClick={() => fileInputRef.current?.click()}
sx={{ py: 4, borderStyle: 'dashed', borderWidth: 2 }} sx={{ py: 4, borderStyle: 'dashed', borderWidth: 2, borderRadius: 2 }}
> >
Select File to Upload Select File to Upload
</Button> </Button>
) : ( ) : (
<Paper variant="outlined" sx={{ p: 2, display: 'flex', alignItems: 'center', justifyContent: 'space-between', bgcolor: 'primary.50' }}> <Paper variant="outlined" sx={{ p: 2, display: 'flex', alignItems: 'center', justifyContent: 'space-between', bgcolor: 'primary.50', borderStyle: 'solid' }}>
<Stack direction="row" spacing={2} alignItems="center"> <Stack direction="row" spacing={2} alignItems="center">
<CloudUploadIcon color="primary" /> <CloudUploadIcon color="primary" />
<Typography variant="body1" fontWeight="500">{selectedFile.name}</Typography> <Typography variant="body1" fontWeight="600">{selectedFile.name}</Typography>
</Stack> </Stack>
<IconButton onClick={() => setSelectedFile(null)} color="error"> <IconButton onClick={() => setSelectedFile(null)} color="error" size="small">
<ClearIcon /> <ClearIcon />
</IconButton> </IconButton>
</Paper> </Paper>
@ -214,35 +216,48 @@ export default function UploadView({ user, folders }: { user: any; folders: any[
<Divider sx={{ my: 4 }} /> <Divider sx={{ my: 4 }} />
{/* MAGIC EXTRACT */} {/* MAGIC EXTRACT SECTION */}
<Box sx={{ mb: 4, p: 2, bgcolor: '#f0f7ff', borderRadius: 2, border: '1px dashed #1976d2' }}> <Box sx={{ mb: 4, p: 2.5, bgcolor: '#f0f7ff', borderRadius: 2, border: '1px dashed #1976d2' }}>
<Stack direction="row" justifyContent="space-between" alignItems="center"> <Stack direction="row" justifyContent="space-between" alignItems="center" spacing={2}>
<Box> <Box>
<Typography variant="subtitle1" fontWeight="bold">Magic Extract</Typography> <Typography variant="subtitle1" fontWeight="bold" color="primary.main">
<Typography variant="caption" color="text.secondary">Populate metadata automatically from file properties.</Typography> Magic Extract
</Typography>
<Typography variant="caption" color="text.secondary">
Automatically pull Author, GPS, and Camera data from the file.
</Typography>
</Box> </Box>
<Button <Button
variant="contained" variant="contained"
onClick={handleMagicEnhance} onClick={handleMagicEnhance}
disabled={!selectedFile || isExtracting} disabled={!selectedFile || isExtracting}
startIcon={isExtracting ? <CircularProgress size={20} color="inherit" /> : <AutoFixHighIcon />} startIcon={isExtracting ? <CircularProgress size={20} color="inherit" /> : <AutoFixHighIcon />}
sx={{ borderRadius: 20, px: 3 }}
> >
{isExtracting ? "Running..." : "Run"} {isExtracting ? "Extracting..." : "Run"}
</Button> </Button>
</Stack> </Stack>
</Box> </Box>
{/* METADATA PREVIEW */} {/* METADATA PREVIEW GRID */}
<Box sx={{ mb: 4 }}> <Box sx={{ mb: 4 }}>
<Typography variant="h6" fontWeight="700" sx={{ mb: 2, display: 'flex', alignItems: 'center', gap: 1 }}> <Typography variant="h6" fontWeight="700" sx={{ mb: 2, display: 'flex', alignItems: 'center', gap: 1 }}>
<AssignmentIcon color="primary" /> Metadata Preview <AssignmentIcon color="primary" /> Metadata Fields
</Typography> </Typography>
{rows.length === 0 && (
<Typography variant="body2" color="text.secondary" sx={{ fontStyle: 'italic', textAlign: 'center', py: 2 }}>
No metadata added yet. Run Magic Extract or add manual fields below.
</Typography>
)}
<Stack spacing={2}> <Stack spacing={2}>
{rows.map((row, index) => ( {rows.map((row, index) => (
<Grid container spacing={1} key={index} alignItems="center"> <Grid container spacing={1} key={index} alignItems="center">
<Grid size={1}> <Grid item xs={1}>
<Checkbox <Checkbox
checked={row.selected} checked={row.selected}
size="small"
onChange={(e) => { onChange={(e) => {
const updated = [...rows]; const updated = [...rows];
updated[index].selected = e.target.checked; updated[index].selected = e.target.checked;
@ -250,9 +265,9 @@ export default function UploadView({ user, folders }: { user: any; folders: any[
}} }}
/> />
</Grid> </Grid>
<Grid size={5}> <Grid item xs={5}>
<TextField <TextField
fullWidth size="small" label="Key" value={row.key} fullWidth size="small" label="Property Name" value={row.key}
onChange={(e) => { onChange={(e) => {
const updated = [...rows]; const updated = [...rows];
updated[index].key = e.target.value; updated[index].key = e.target.value;
@ -260,7 +275,7 @@ export default function UploadView({ user, folders }: { user: any; folders: any[
}} }}
/> />
</Grid> </Grid>
<Grid size={5}> <Grid item xs={5}>
<TextField <TextField
fullWidth size="small" label="Value" value={row.value} fullWidth size="small" label="Value" value={row.value}
onChange={(e) => { onChange={(e) => {
@ -270,36 +285,43 @@ export default function UploadView({ user, folders }: { user: any; folders: any[
}} }}
/> />
</Grid> </Grid>
<Grid size={1}> <Grid item xs={1}>
<IconButton onClick={() => setRows(rows.filter((_, i) => i !== index))} color="error"> <IconButton onClick={() => setRows(rows.filter((_, i) => i !== index))} color="error" size="small">
<DeleteOutlineIcon /> <DeleteOutlineIcon />
</IconButton> </IconButton>
</Grid> </Grid>
</Grid> </Grid>
))} ))}
<Button <Button
variant="text" variant="text"
startIcon={<AddCircleOutlineIcon />} startIcon={<AddCircleOutlineIcon />}
onClick={() => setRows([...rows, {key: "", value: "", selected: true}])} onClick={() => setRows([...rows, {key: "", value: "", selected: true}])}
sx={{ alignSelf: 'flex-start', mt: 1 }}
> >
Add Manual Field Add Manual Field
</Button> </Button>
</Stack> </Stack>
</Box> </Box>
{/* UPLOAD BUTTON */} {/* ACTION BUTTON */}
<Button <Button
variant="contained" variant="contained"
size="large" size="large"
fullWidth fullWidth
onClick={handleSave} onClick={handleSave}
disabled={!canSubmit || saveStatus === 'saving'} disabled={!canSubmit || saveStatus === 'saving'}
sx={{ py: 2, fontWeight: 'bold' }} sx={{
py: 2,
fontWeight: 'bold',
borderRadius: 2,
boxShadow: 4
}}
> >
{saveStatus === 'saving' ? ( {saveStatus === 'saving' ? (
<Stack direction="row" spacing={2} alignItems="center"> <Stack direction="row" spacing={2} alignItems="center">
<CircularProgress size={24} color="inherit" /> <CircularProgress size={24} color="inherit" />
<Typography>Processing Upload...</Typography> <Typography>Creating Folder & Uploading...</Typography>
</Stack> </Stack>
) : ( ) : (
"Complete Upload & Save" "Complete Upload & Save"