feat: add FileDescriptionContainer for managing file descriptions and integrate with FileActions

This commit is contained in:
ZareMate 2025-05-04 17:00:56 +02:00
parent 344334592e
commit 1d302eb217
Signed by: zaremate
GPG Key ID: 369A0E45E03A81C3
4 changed files with 49 additions and 10 deletions

View File

@ -1,5 +1,6 @@
'use client';
import {useFileActions} from "~/app/_components/FileActions";
import { useRef, useState } from "react";
import { useFileActions } from "~/app/_components/FileActions";
export function FileActionsContainer({
fileId,
@ -12,7 +13,7 @@ export function FileActionsContainer({
fileUrl: string;
isOwner: boolean;
}) {
const { handleDownload, handleCopyUrl, handleRemove } = useFileActions(() => fileId, (description: string) => {
const { handleDownload, handleCopyUrl, handleRemove} = useFileActions(() => fileId, (description: string) => {
if (isOwner) {
console.log(description);
}
@ -84,4 +85,36 @@ export function FileActionsContainer({
</button>
</div>
);
}
export function FileDescriptionContainer({
fileId,
fileDescriprtion,
}: {
fileId: string;
fileDescriprtion?: string;
}) {
const [description, setDescription] = useState(fileDescriprtion || ""); // Add state for description
const { handleDescriptionChange } = useFileActions(() => {}, (description: string) => {
setDescription(description);
return undefined;
}, fileId); // Wrap setDescription in a function
const debounceTimer = useRef<NodeJS.Timeout | null>(null); // Initialize debounce timer
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
handleDescriptionChange(e, debounceTimer); // Pass the debounce timer
};
return (
<div className="flex self-center gap-2">
<textarea
className="w-full h-24 p-2 border rounded-md bg-gray-800 text-white"
value={description} // Use state value
onChange={handleChange}
placeholder="Enter file description..."
maxLength={200} // Limit to 200 characters
/>
</div>
);
}

View File

@ -4,7 +4,7 @@ import { notifyClients } from "~/utils/notifyClients";
export const useFileActions = (
setFiles: (callback: (prevFiles: any[]) => any[]) => void,
setDescription?: (description: string) => void,
setDescription?: (description: string) => undefined,
fileId?: string
) => {
const pageUrl = `${env.NEXT_PUBLIC_PAGE_URL}`;
@ -75,7 +75,9 @@ export const useFileActions = (
e: React.ChangeEvent<HTMLTextAreaElement>,
debounceTimer: React.RefObject<NodeJS.Timeout | null>
) => {
if (!setDescription) return;
if (setDescription === undefined) {console.error("setDescription function is not provided")
return;
};
const newDescription = e.target.value;
setDescription(newDescription);
@ -83,7 +85,9 @@ export const useFileActions = (
if (debounceTimer.current) {
clearTimeout(debounceTimer.current);
}
debounceTimer.current = setTimeout(() => {
console.log("Calling handleDescriptionSave"); // Debug log
handleDescriptionSave(newDescription);
}, 1000);
};
@ -99,7 +103,8 @@ export const useFileActions = (
const response = await fetch(`/api/files/share?id=${encodeURIComponent(fileId)}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ description }),
// pass the fileId and description in the request body
body: JSON.stringify({ description, id: fileId }),
});
if (response.status === 403) {

View File

@ -48,7 +48,8 @@ export async function PUT(req: Request) {
try {
const body = (await req.json()) as { id: string; description: string } | null;
if (!body?.id || !body.description) {
if (!body?.id || body.description === undefined) {
// Allow empty description but ensure id is present
return NextResponse.json({ error: "Invalid request body" }, { status: 400 });
}

View File

@ -2,7 +2,7 @@ import { notFound } from "next/navigation";
import { FilePreview } from "~/app/_components/FilePreview";
import { HomeButton } from "~/app/_components/HomeButton"; // Import the client component
import { Toaster } from "react-hot-toast";
import { FileActionsContainer } from "~/app/_components/ActionButtons"; // Import the client component
import { FileActionsContainer, FileDescriptionContainer } from "~/app/_components/ActionButtons"; // Import the client component
import Head from "next/head";
interface FileDetails {
@ -143,10 +143,10 @@ export default async function FilePreviewContainer({
<strong>Upload Date:</strong>{" "}
{new Date(fileDetails.uploadDate).toLocaleString()}
</p>
<p>
<div>
<strong>Description:</strong>{" "}
{fileDetails.description || "No description available"}
</p>
<FileDescriptionContainer fileId={fileDetails.id} fileDescriprtion={fileDetails.description}/>
</div>
<div className="mt-4 flex justify-center">
<FileActionsContainer
fileId={fileDetails.id}