Files
local-cal/src/components/drag-drop-container.tsx
Dmytro Stanchiev 276fbad45e chore: legacy cleanup
Signed-off-by: Dmytro Stanchiev <git@dmytros.dev>
2026-04-21 20:24:04 -04:00

95 lines
2.4 KiB
TypeScript

"use client";
import { AnimatePresence, motion } from "framer-motion";
import { FileUp } from "lucide-react";
import type { ReactNode } from "react";
import { toast } from "sonner";
import { IMAGE_EXTENSIONS } from "@/lib/constants";
const getFileType = (file: File): "ics" | "image" | null => {
const name = file.name.toLowerCase();
if (name.endsWith(".ics")) return "ics";
if (IMAGE_EXTENSIONS.some((ext) => name.endsWith(ext))) return "image";
return null;
};
interface DragDropContainerProps {
children: ReactNode;
isDragOver: boolean;
setIsDragOver: (isDragOver: boolean) => void;
onImport: (file: File) => void;
onImageDrop?: (file: File) => void;
}
export const DragDropContainer = ({
children,
isDragOver,
setIsDragOver,
onImport,
onImageDrop,
}: DragDropContainerProps) => {
const handleDragOver = (e: React.DragEvent) => {
e.preventDefault();
setIsDragOver(true);
};
const handleDragLeave = (e: React.DragEvent) => {
e.preventDefault();
setIsDragOver(false);
};
const handleDrop = (e: React.DragEvent) => {
e.preventDefault();
setIsDragOver(false);
if (e.dataTransfer.files?.length) {
const file = e.dataTransfer.files[0];
const fileType = getFileType(file);
if (fileType === "ics") {
onImport(file);
} else if (fileType === "image" && onImageDrop) {
onImageDrop(file);
} else {
toast.warning("Drop an .ics file or an event screenshot");
}
}
};
return (
<section
aria-label="Drag and drop file import area"
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
className="relative flex flex-col"
>
<AnimatePresence>
{isDragOver && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.15 }}
className="absolute inset-0 z-40 flex items-center justify-center rounded-[10px] border-2 border-dashed border-primary/40 bg-background/92"
>
<div className="flex flex-col items-center gap-2 text-primary">
<FileUp className="h-8 w-8" />
<span className="text-sm font-medium">
Drop .ics or image here
</span>
</div>
</motion.div>
)}
</AnimatePresence>
{children}
<div className="pt-6 pb-2">
<p className="text-center text-xs text-muted-foreground/40">
Drag & drop .ics files or event screenshots
</p>
</div>
</section>
);
};