import { createSignal, createEffect, For, Show } from "solid-js"; import Dropzone from "./Dropzone"; import AttachmentThumbnail from "~/components/ui/AttachmentThumbnail"; import AddImageToS3 from "~/lib/s3upload"; import { env } from "~/env/client"; import { api } from "~/lib/api"; export interface AddAttachmentSectionProps { type: "blog" | "project"; postId?: number; postTitle: string; existingAttachments?: string; } export default function AddAttachmentSection(props: AddAttachmentSectionProps) { const [files, setFiles] = createSignal([]); const [s3Files, setS3Files] = createSignal< Array<{ key: string; size: number; lastModified: string }> >([]); const [newFileHolder, setNewFileHolder] = createSignal([]); const [newFileHolderKeys, setNewFileHolderKeys] = createSignal([]); const [fileTypes, setFileTypes] = createSignal([]); const [loading, setLoading] = createSignal(false); createEffect(() => { if (props.postTitle) { loadAttachments(); } }); const loadAttachments = async () => { setLoading(true); try { const result = await api.misc.listAttachments.query({ type: props.type, title: props.postTitle }); setS3Files(result.files); } catch (err) { console.error("Failed to load attachments:", err); } finally { setLoading(false); } }; const handleImageDrop = async (acceptedFiles: File[]) => { if (props.postTitle) { for (const file of acceptedFiles) { setFiles((prev) => [...prev, file]); try { const key = await AddImageToS3(file, props.postTitle, props.type); if (key) { setNewFileHolderKeys((prev) => [...prev, key]); const reader = new FileReader(); reader.onload = () => { const str = reader.result; if (str) { setNewFileHolder((prev) => [...prev, str as string]); setFileTypes((prev) => [...prev, file.type]); } }; reader.readAsDataURL(file); await loadAttachments(); } } catch (err) { console.error("Failed to upload file:", err); } } } }; const removeImage = async (key: string) => { try { await fetch("/api/trpc/misc.simpleDeleteImage", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ key }) }); await loadAttachments(); } catch (err) { console.error("Failed to delete file:", err); } }; const removeNewImage = async (index: number, key: string) => { setFiles((prev) => prev.filter((_, i) => i !== index)); setNewFileHolder((prev) => prev.filter((_, i) => i !== index)); setFileTypes((prev) => prev.filter((_, i) => i !== index)); try { await fetch("/api/trpc/misc.simpleDeleteImage", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ key }) }); } catch (err) { console.error("Failed to delete file:", err); } }; const copyToClipboard = async (key: string) => { try { const bucketString = env.VITE_AWS_BUCKET_STRING || ""; await navigator.clipboard.writeText(bucketString + key); console.log("Text copied to clipboard"); } catch (err) { console.error("Failed to copy text:", err); } }; const getFileUrl = (key: string) => { const bucketString = env.VITE_AWS_BUCKET_STRING || ""; return bucketString + key; }; const isVideoFile = (url: string) => { return url.match(/\.(mp4|webm|mov)$/i) !== null; }; return ( Add title to add attachments } >
Attachments
Loading attachments...
{(file) => ( copyToClipboard(file.key)} onRemove={() => removeImage(file.key)} alt="attachment" /> )} 0}>
{(file, index) => ( copyToClipboard(newFileHolderKeys()[index()] as string) } onRemove={() => removeNewImage(index(), newFileHolderKeys()[index()]) } alt="new attachment" /> )}
); }