Updated files path to dynamically load new files.
This commit is contained in:
1 parent
ead6b5a9f7
commit
db6303e206
14 files changed
+77
-36
No files matched your search
@@ -1,10 +1,14 @@
|
||||
// app/actions/files.ts
|
||||
'use server';
|
||||
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
import fsPromises from 'fs/promises';
|
||||
import path from 'path';
|
||||
import crypto from 'crypto';
|
||||
|
||||
const isProd = process.env.NODE_ENV === "production";
|
||||
const DATA_DIR = isProd ? "/app/data" : path.join(process.cwd(), "app/data");
|
||||
const FILES_DIR = path.join(DATA_DIR, "files");
|
||||
|
||||
const generateFileHash = (filePath: string): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -19,15 +23,15 @@ const generateFileHash = (filePath: string): Promise<string> => {
|
||||
|
||||
export async function getLocalFileMeta(fileUrl: string) {
|
||||
try {
|
||||
const cleanPath = fileUrl.startsWith('/') ? fileUrl.substring(1) : fileUrl;
|
||||
const fullPath = path.join(process.cwd(), 'public', cleanPath);
|
||||
const cleanName = decodeURIComponent(fileUrl.split('/').pop() || '');
|
||||
const fullPath = path.join(FILES_DIR, cleanName);
|
||||
const stats = await fsPromises.stat(fullPath);
|
||||
const sizeMb = (stats.size / (1024 * 1024)).toFixed(2) + ' MB';
|
||||
const fileHash = await generateFileHash(fullPath);
|
||||
|
||||
return { size: sizeMb, version: fileHash };
|
||||
} catch (error) {
|
||||
console.error(`Kunde inte läsa filen: ${fileUrl}`, error);
|
||||
console.error(`Kunde inte läsa filen (actions): ${fileUrl}`, error);
|
||||
return { size: "Okänd", version: "v1" };
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,8 @@ export function DocumentCard({ doc, isOffline, isCached }: DocumentCardProps) {
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={`group flex items-center justify-between p-4 rounded-2xl border transition-colors ${isOffline && !isCached
|
||||
? 'opacity-50 grayscale cursor-not-allowed pointer-events-none border-transparent bg-eggshell/50'
|
||||
: 'bg-white/50 hover:bg-white border-slate-teal/10'
|
||||
? 'opacity-50 grayscale cursor-not-allowed pointer-events-none border-transparent bg-eggshell/50'
|
||||
: 'bg-white/50 hover:bg-white border-slate-teal/10'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center text-slate-teal">
|
||||
@@ -74,8 +74,8 @@ export function ExternalLinkCard({ link, isOffline }: ExternalLinkCardProps) {
|
||||
target={isOffline ? '_self' : '_blank'}
|
||||
rel="noopener noreferrer"
|
||||
className={`group flex items-center justify-between p-4 rounded-2xl border transition-colors ${isOffline
|
||||
? 'opacity-40 grayscale cursor-not-allowed pointer-events-none bg-eggshell/50 border-transparent'
|
||||
: 'bg-white/50 hover:bg-white border-slate-teal/10'
|
||||
? 'opacity-40 grayscale cursor-not-allowed pointer-events-none bg-eggshell/50 border-transparent'
|
||||
: 'bg-white/50 hover:bg-white border-slate-teal/10'
|
||||
}`}
|
||||
>
|
||||
<span className="font-bold text-slate-teal text-sm leading-tight pr-4">{link.title}</span>
|
||||
|
||||
+20
-6
@@ -3,32 +3,42 @@
|
||||
{
|
||||
"title": "Turistkarta",
|
||||
"icon": "Map",
|
||||
"file": "/files/Turistkarta - Kullaberg.pdf"
|
||||
"file": "Turistkarta - Kullaberg.pdf"
|
||||
},
|
||||
{
|
||||
"title": "Orienteringskarta",
|
||||
"icon": "MapPlus",
|
||||
"file": "/files/Orienteringskarta - Kullaberg.pdf"
|
||||
"file": "Orienteringskarta - Kullaberg.pdf"
|
||||
},
|
||||
{
|
||||
"title": "Badplatser att besöka",
|
||||
"icon": "WavesLadder",
|
||||
"file": "/files/Badplatser på Kullaberg.pdf"
|
||||
"file": "Badplatser på Kullaberg.pdf"
|
||||
},
|
||||
{
|
||||
"title": "Vandringsrutter",
|
||||
"icon": "MapPinned",
|
||||
"file": "/files/Vandringsrutter.pdf"
|
||||
"file": "Vandringsrutter.pdf"
|
||||
},
|
||||
{
|
||||
"title": "Underlag för guidediplomering",
|
||||
"icon": "BookCopy",
|
||||
"file": "/files/Underlag för guidediplomering.pdf"
|
||||
"file": "Underlag för guidediplomering.pdf"
|
||||
},
|
||||
{
|
||||
"title": "Destinationskunskap Kullahalvön",
|
||||
"icon": "BookCopy",
|
||||
"file": "/files/Destinationskunskap.pdf"
|
||||
"file": "Destinationskunskap.pdf"
|
||||
},
|
||||
{
|
||||
"title": "Tjänstgöringsrapport",
|
||||
"icon": "BookCopy",
|
||||
"file": "Tjänstgöringsrapport 2026.pdf"
|
||||
},
|
||||
{
|
||||
"title": "Information om ditt sommarjobb",
|
||||
"icon": "BookCopy",
|
||||
"file": "Information om ditt sommarjobb 2026.pdf"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
@@ -48,6 +58,10 @@
|
||||
"title": "Skåneleden",
|
||||
"url": "https://www.skaneleden.se/en"
|
||||
},
|
||||
{
|
||||
"title": "RSNV Brandriskprognos",
|
||||
"url": "https://rsnv.se/brandriskprognos/"
|
||||
},
|
||||
{
|
||||
"title": "Väderprognos Mölle",
|
||||
"url": "https://www.smhi.se/vader/prognoser-och-varningar/vaderprognos/q/H%C3%B6gan%C3%A4s/M%C3%B6lle/2691501"
|
||||
|
||||
File renamed without changes.
Binary file not shown.
Binary file not shown.
File renamed without changes.
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2
-22
@@ -19,27 +19,6 @@ const IconMap: Record<string, any> = {
|
||||
"FileText": FileText
|
||||
};
|
||||
|
||||
const fetchFileMeta = async (url: string) => {
|
||||
try {
|
||||
const res = await fetch(url, { method: 'HEAD', cache: 'no-store' });
|
||||
const bytes = res.headers.get('content-length');
|
||||
const lastModified = res.headers.get('last-modified');
|
||||
const etag = res.headers.get('etag');
|
||||
|
||||
let sizeStr = "Okänd";
|
||||
if (bytes) {
|
||||
const mb = (parseInt(bytes) / (1024 * 1024)).toFixed(2);
|
||||
sizeStr = `${mb} MB`;
|
||||
}
|
||||
const version = etag ? etag.replace(/"/g, '') :
|
||||
(lastModified ? new Date(lastModified).getTime().toString() : 'v1');
|
||||
|
||||
return { size: sizeStr, version };
|
||||
} catch (error) {
|
||||
return { size: "Okänd", version: "v1" };
|
||||
}
|
||||
};
|
||||
|
||||
export default function Documents() {
|
||||
const [isHydrated, setIsHydrated] = useState(false);
|
||||
const [isOffline, setIsOffline] = useState(false);
|
||||
@@ -73,7 +52,8 @@ export default function Documents() {
|
||||
const docsWithMeta = await Promise.all(
|
||||
(res.data.docs || []).map(async (doc: DocumentItem) => {
|
||||
const meta = await getLocalFileMeta(doc.file);
|
||||
const versionedUrl = `${doc.file}?v=${meta.version}`;
|
||||
const fileNameOnly = doc.file.split('/').pop();
|
||||
const versionedUrl = `/files/${fileNameOnly}?v=${meta.version}`;
|
||||
|
||||
return {
|
||||
...doc,
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// app/files/[...slug]/route.ts
|
||||
|
||||
import fs from 'fs';
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import path from 'path';
|
||||
|
||||
const isProd = process.env.NODE_ENV === "production";
|
||||
const DATA_DIR = isProd ? "/app/data" : path.join(process.cwd(), "app/data");
|
||||
const FILES_DIR = path.join(DATA_DIR, "files");
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ slug: string[] }> }
|
||||
) {
|
||||
try {
|
||||
const resolvedParams = await params;
|
||||
const filename = decodeURIComponent(resolvedParams.slug[resolvedParams.slug.length - 1]);
|
||||
const filePath = path.join(FILES_DIR, filename);
|
||||
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.error(`404 - Filen finns inte på disk: ${filePath}`);
|
||||
return new NextResponse('Filen hittades inte', { status: 404 });
|
||||
}
|
||||
|
||||
const fileBuffer = fs.readFileSync(filePath);
|
||||
|
||||
let contentType = 'application/pdf';
|
||||
if (filename.toLowerCase().endsWith('.png')) contentType = 'image/png';
|
||||
else if (filename.toLowerCase().endsWith('.jpg') || filename.toLowerCase().endsWith('.jpeg')) contentType = 'image/jpeg';
|
||||
else if (filename.toLowerCase().endsWith('.doc') || filename.toLowerCase().endsWith('.docx')) contentType = 'application/msword';
|
||||
|
||||
return new NextResponse(fileBuffer, {
|
||||
headers: {
|
||||
'Content-Type': contentType,
|
||||
'Content-Disposition': `inline; filename="${filename}"`
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Fel vid fildelning:", error);
|
||||
return new NextResponse('Ett internt serverfel uppstod', { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ const nextConfig: NextConfig = {
|
||||
output: "standalone",
|
||||
allowedDevOrigins: [
|
||||
'10.10.0.121',
|
||||
'10.11.0.122',
|
||||
'localhost',
|
||||
],
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user