171 lines
5.9 KiB
TypeScript
171 lines
5.9 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { useState } from "react";
|
||
|
|
import {
|
||
|
|
Box, Button, Typography, Paper, Stack,
|
||
|
|
TextField, MenuItem, IconButton, Grid, Divider
|
||
|
|
} from "@mui/material";
|
||
|
|
import SaveIcon from "@mui/icons-material/Save";
|
||
|
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||
|
|
import AssignmentIcon from '@mui/icons-material/Assignment';
|
||
|
|
import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline';
|
||
|
|
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
|
||
|
|
import FolderIcon from "@mui/icons-material/Folder";
|
||
|
|
import { useRouter } from "next/navigation";
|
||
|
|
import { updateFileAction } from "./_actions";
|
||
|
|
|
||
|
|
interface MetadataPair {
|
||
|
|
key: string;
|
||
|
|
value: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export default function UpdateView({ fileNode, folders }: any) {
|
||
|
|
const router = useRouter();
|
||
|
|
const [loading, setLoading] = useState(false);
|
||
|
|
|
||
|
|
// 1. Initialize Basic Info
|
||
|
|
const [name, setName] = useState(fileNode.name);
|
||
|
|
const [description, setDescription] = useState(fileNode.description || "");
|
||
|
|
const [parentId, setParentId] = useState(fileNode.parentId || "");
|
||
|
|
|
||
|
|
// 2. Parse existing JSON metadata into Key/Value array for the UI
|
||
|
|
// We filter out 'type' and 'mimeType' as they are system-managed
|
||
|
|
const initialMetadata = Object.entries(fileNode.metadata || {})
|
||
|
|
.filter(([key]) => !['type', 'mimeType'].includes(key))
|
||
|
|
.map(([key, value]) => ({ key, value: String(value) }));
|
||
|
|
|
||
|
|
const [customMetadata, setCustomMetadata] = useState<MetadataPair[]>(initialMetadata);
|
||
|
|
|
||
|
|
const handleUpdate = async () => {
|
||
|
|
setLoading(true);
|
||
|
|
const formData = new FormData();
|
||
|
|
formData.append("id", fileNode.id);
|
||
|
|
formData.append("name", name);
|
||
|
|
formData.append("description", description);
|
||
|
|
formData.append("parentId", parentId);
|
||
|
|
|
||
|
|
// Convert array back to object for storage
|
||
|
|
const metadataObj = customMetadata.reduce((acc, curr) => {
|
||
|
|
if (curr.key.trim()) acc[curr.key.trim()] = curr.value;
|
||
|
|
return acc;
|
||
|
|
}, {} as Record<string, string>);
|
||
|
|
|
||
|
|
formData.append("customMetadata", JSON.stringify(metadataObj));
|
||
|
|
|
||
|
|
const res = await updateFileAction(formData);
|
||
|
|
if (res.success) {
|
||
|
|
router.push("/dashboard");
|
||
|
|
router.refresh();
|
||
|
|
} else {
|
||
|
|
alert("Update failed");
|
||
|
|
setLoading(false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Paper sx={{ p: { xs: 3, md: 6 }, borderRadius: 4 }} elevation={3}>
|
||
|
|
<Button startIcon={<ArrowBackIcon />} onClick={() => router.back()} sx={{ mb: 2 }}>
|
||
|
|
Back
|
||
|
|
</Button>
|
||
|
|
|
||
|
|
<Typography variant="h4" fontWeight={900} color="primary" gutterBottom>
|
||
|
|
Edit File Details
|
||
|
|
</Typography>
|
||
|
|
|
||
|
|
<Stack spacing={4} sx={{ mt: 2 }}>
|
||
|
|
{/* Name Field */}
|
||
|
|
<TextField
|
||
|
|
label="File Name"
|
||
|
|
fullWidth value={name}
|
||
|
|
onChange={(e) => setName(e.target.value)}
|
||
|
|
slotProps={{ inputLabel: { shrink: true } }}
|
||
|
|
/>
|
||
|
|
|
||
|
|
{/* Folder Select */}
|
||
|
|
<TextField
|
||
|
|
id="update-dest-select"
|
||
|
|
select fullWidth label="Destination Folder"
|
||
|
|
value={parentId}
|
||
|
|
onChange={(e) => setParentId(e.target.value)}
|
||
|
|
slotProps={{
|
||
|
|
select: { displayEmpty: true },
|
||
|
|
inputLabel: { shrink: true }
|
||
|
|
}}
|
||
|
|
>
|
||
|
|
<MenuItem value=""><em>-- Root --</em></MenuItem>
|
||
|
|
{folders.map((f: any) => (
|
||
|
|
<MenuItem key={f.id} value={f.id}>{f.name}</MenuItem>
|
||
|
|
))}
|
||
|
|
</TextField>
|
||
|
|
|
||
|
|
{/* Custom Metadata Section */}
|
||
|
|
<Box>
|
||
|
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
|
||
|
|
<Typography variant="h6" fontWeight="700" sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||
|
|
<AssignmentIcon color="primary" /> Custom Attributes
|
||
|
|
</Typography>
|
||
|
|
<Button
|
||
|
|
startIcon={<AddCircleOutlineIcon />}
|
||
|
|
size="small"
|
||
|
|
onClick={() => setCustomMetadata([...customMetadata, { key: "", value: "" }])}
|
||
|
|
>
|
||
|
|
Add Field
|
||
|
|
</Button>
|
||
|
|
</Box>
|
||
|
|
|
||
|
|
<Stack spacing={2}>
|
||
|
|
{customMetadata.map((row, index) => (
|
||
|
|
<Grid container spacing={1} key={index} alignItems="center">
|
||
|
|
<Grid item xs={5}>
|
||
|
|
<TextField
|
||
|
|
fullWidth size="small" placeholder="Key"
|
||
|
|
value={row.key}
|
||
|
|
onChange={(e) => {
|
||
|
|
const updated = [...customMetadata];
|
||
|
|
updated[index].key = e.target.value;
|
||
|
|
setCustomMetadata(updated);
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
</Grid>
|
||
|
|
<Grid item xs={6}>
|
||
|
|
<TextField
|
||
|
|
fullWidth size="small" placeholder="Value"
|
||
|
|
value={row.value}
|
||
|
|
onChange={(e) => {
|
||
|
|
const updated = [...customMetadata];
|
||
|
|
updated[index].value = e.target.value;
|
||
|
|
setCustomMetadata(updated);
|
||
|
|
}}
|
||
|
|
/>
|
||
|
|
</Grid>
|
||
|
|
<Grid item xs={1}>
|
||
|
|
<IconButton color="error" onClick={() => setCustomMetadata(customMetadata.filter((_, i) => i !== index))}>
|
||
|
|
<DeleteOutlineIcon />
|
||
|
|
</IconButton>
|
||
|
|
</Grid>
|
||
|
|
</Grid>
|
||
|
|
))}
|
||
|
|
</Stack>
|
||
|
|
</Box>
|
||
|
|
|
||
|
|
<TextField
|
||
|
|
label="Description"
|
||
|
|
multiline rows={4} fullWidth
|
||
|
|
value={description}
|
||
|
|
onChange={(e) => setDescription(e.target.value)}
|
||
|
|
slotProps={{ inputLabel: { shrink: true } }}
|
||
|
|
/>
|
||
|
|
|
||
|
|
<Button
|
||
|
|
variant="contained" size="large" fullWidth
|
||
|
|
startIcon={<SaveIcon />}
|
||
|
|
onClick={handleUpdate}
|
||
|
|
disabled={loading}
|
||
|
|
sx={{ py: 1.5, fontWeight: 'bold' }}
|
||
|
|
>
|
||
|
|
{loading ? "Saving..." : "Save Changes"}
|
||
|
|
</Button>
|
||
|
|
</Stack>
|
||
|
|
</Paper>
|
||
|
|
);
|
||
|
|
}
|