From 96eda53f317bda260e6556b6c46fd04a8baf12be Mon Sep 17 00:00:00 2001 From: stephen Date: Thu, 12 Feb 2026 22:55:43 +1100 Subject: [PATCH] File detail page addedd --- src/app/dashboard/dashboard-view.tsx | 37 ++++++-- src/app/dashboard/files/[id]/page.tsx | 132 ++++++++++++++++++++++++++ src/lib/text.pdf | Bin 13966 -> 0 bytes src/lib/transformers.ts | 52 ++++++++++ 4 files changed, 211 insertions(+), 10 deletions(-) create mode 100644 src/app/dashboard/files/[id]/page.tsx delete mode 100644 src/lib/text.pdf diff --git a/src/app/dashboard/dashboard-view.tsx b/src/app/dashboard/dashboard-view.tsx index 0ea7e47..bf38917 100644 --- a/src/app/dashboard/dashboard-view.tsx +++ b/src/app/dashboard/dashboard-view.tsx @@ -1,5 +1,5 @@ 'use client'; - +// src/app/dashboard-view.tsx import { useState } from "react"; import { styled } from '@mui/material/styles'; import { @@ -21,6 +21,7 @@ import { QuickFilter, QuickFilterControl, QuickFilterClear, + GridEventListener, } from "@mui/x-data-grid"; import SyncIcon from "@mui/icons-material/Sync"; import RefreshIcon from "@mui/icons-material/Refresh"; @@ -156,6 +157,14 @@ export default function DashboardView({ initialFiles, user }: DashboardViewProps } }; + // --- NEW: Double Click Handler --- + const handleRowDoubleClick: GridEventListener<'rowDoubleClick'> = (params) => { + // Only navigate if it's a file. If it's a folder, we could eventually navigate into it. + if (!params.row.isFolder) { + router.push(`/dashboard/files/${params.id}`); + } + }; + const columns: GridColDef[] = [ { field: "name", @@ -163,10 +172,12 @@ export default function DashboardView({ initialFiles, user }: DashboardViewProps flex: 1.5, minWidth: 250, renderCell: (params) => ( - - {params.row.isFolder ? : } - {params.value} - + + + {params.row.isFolder ? : } + {params.value} + + ) }, { @@ -211,20 +222,20 @@ export default function DashboardView({ initialFiles, user }: DashboardViewProps {!isFolder && ( <> - window.open(`/api/download?id=${params.row.id}&mode=inline`, '_blank')}> + { e.stopPropagation(); window.open(`/api/download?id=${params.row.id}&mode=inline`, '_blank'); }}> - window.location.href = `/api/download?id=${params.row.id}&mode=attachment`}> + { e.stopPropagation(); window.location.href = `/api/download?id=${params.row.id}&mode=attachment`; }}> )} {(isAdmin || isOwner) && ( <> - router.push(`/update/${params.row.id}`)}> + { e.stopPropagation(); router.push(`/update/${params.row.id}`); }}> - handleDelete(params.row.id, params.row.name)}> + { e.stopPropagation(); handleDelete(params.row.id, params.row.name); }}> @@ -273,6 +284,7 @@ export default function DashboardView({ initialFiles, user }: DashboardViewProps showToolbar slots={{ toolbar: CustomToolbar }} disableRowSelectionOnClick + onRowDoubleClick={handleRowDoubleClick} // ADDED THIS HANDLER initialState={{ columns: { columnVisibilityModel: { @@ -280,7 +292,12 @@ export default function DashboardView({ initialFiles, user }: DashboardViewProps }, }, }} - sx={{ border: 'none' }} + sx={{ + border: 'none', + '& .MuiDataGrid-row:hover': { + cursor: 'pointer', + }, + }} /> diff --git a/src/app/dashboard/files/[id]/page.tsx b/src/app/dashboard/files/[id]/page.tsx new file mode 100644 index 0000000..9a8df92 --- /dev/null +++ b/src/app/dashboard/files/[id]/page.tsx @@ -0,0 +1,132 @@ +// src/app/dashboard/files/[id]/page.tsx +import { getFileNodeById } from "@/data-access/file-nodes"; +import { mapMetadata } from "@/lib/transformers"; +import { notFound } from "next/navigation"; +import { + Box, Container, Typography, Paper, Grid, Divider, Stack, Button +} from "@mui/material"; +import DescriptionIcon from '@mui/icons-material/Description'; +import PhotoIcon from '@mui/icons-material/Photo'; +import ArrowBackIcon from '@mui/icons-material/ArrowBack'; +import Link from "next/link"; + +export default async function FileDetailPage(props: { + params: Promise<{ id: string }> +}) { + // 1. Unwrapping params for Next.js 15/16+ + const { id } = await props.params; + + // 2. Fetch data via DAL + const file = await getFileNodeById(id); + + // 3. Check schema-correct property 'isFolder' + if (!file || file.isFolder) { + notFound(); + } + + // 4. Transform data for the UI + const data = mapMetadata(file); + + // 5. Derived extension logic + const extension = file.name.split('.').pop()?.toLowerCase(); + const isPDF = extension === 'pdf'; + + // 6. Handle BigInt for Size + const sizeKB = file.size ? (Number(file.size) / 1024).toFixed(2) : "0"; + + return ( + + {/* Navigation back to dashboard */} + + + + + + + {isPDF ? ( + + ) : ( + + )} + + {file.name} + + ID: {file.id} + + + + + + {/* Left Column: Core Info & Preview */} + + Summary + + + {data.textPreview && ( + + + DOCUMENT PREVIEW + + + "{data.textPreview}..." + + + )} + + + + FILE TYPE + {data.type} + + + SIZE + {sizeKB} KB + + {data.pageCount > 0 && ( + + PAGE COUNT + {data.pageCount} + + )} + + UPLOADED AT + + {new Date(file.createdAt).toLocaleString()} + + + + + + {/* Right Column: Deep Metadata */} + + Extracted Attributes + + + {Object.entries(file.metadata as Record || {}).map(([key, value]) => ( + + + {key} + + + {typeof value === 'object' ? JSON.stringify(value) : String(value)} + + + ))} + {/* FIXED: Properly closed logic for empty metadata */} + {Object.keys(file.metadata as object || {}).length === 0 && ( + + No extra metadata extracted for this file. + + )} + + + + + + ); +} \ No newline at end of file diff --git a/src/lib/text.pdf b/src/lib/text.pdf deleted file mode 100644 index 9910af6391566880d61a4b433c55a45e986ad4a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13966 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 RdPWvzdKeNCVObHF{|}-B24MgI diff --git a/src/lib/transformers.ts b/src/lib/transformers.ts index 5431867..375846b 100644 --- a/src/lib/transformers.ts +++ b/src/lib/transformers.ts @@ -56,4 +56,56 @@ export const mapImageMetadata = (metadata: any) => { : null } }; +}; + +// src/lib/transformers.ts + +/** + * Transforms the raw database FileNode into a structured object for the UI. + */ +export const mapMetadata = (node: any) => { + if (!node) return { title: "Unknown File" }; + + const meta = node.metadata || {}; + const fileName = node.name; + const extension = fileName.split('.').pop()?.toLowerCase(); + + // --- PDF Logic --- + if (extension === 'pdf') { + return { + fileName, + type: 'PDF Document', + title: meta.title || fileName, + author: meta.author || 'Unknown Author', + subject: meta.subject || 'N/A', + pageCount: meta.pageCount || 0, + keywords: meta.keywords || 'None', + textPreview: node.description || meta.textPreview || '', // description field often stores the preview + creator: meta.creator || 'N/A', + producer: meta.producer || 'N/A' + }; + } + + // --- Image Logic (Sharp/Exif) --- + if (['jpg', 'jpeg', 'png', 'webp'].includes(extension || '')) { + // Note: your extractor lowercase keys via the sanitizer + return { + fileName, + type: 'Image', + device: `${meta.image?.make || ''} ${meta.image?.model || ''}`.trim() || 'Unknown Device', + timestamp: meta.photo?.dateTimeOriginal ? new Date(meta.photo.dateTimeOriginal) : null, + settings: { + aperture: meta.photo?.fNumber ? `f/${meta.photo.fNumber}` : 'N/A', + iso: meta.photo?.iSOSpeedRatings || 'N/A', + focalLength: meta.photo?.focalLength ? `${meta.photo.focalLength}mm` : 'N/A', + } + }; + } + + // --- Default Fallback --- + return { + fileName, + type: extension?.toUpperCase() || 'File', + details: meta + }; }; \ No newline at end of file